summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile40
-rw-r--r--usr.sbin/Makefile.inc3
-rw-r--r--usr.sbin/XNSrouted/Makefile9
-rw-r--r--usr.sbin/XNSrouted/XNSrouted.8186
-rw-r--r--usr.sbin/XNSrouted/af.c246
-rw-r--r--usr.sbin/XNSrouted/af.h64
-rw-r--r--usr.sbin/XNSrouted/defs.h94
-rw-r--r--usr.sbin/XNSrouted/if.c147
-rw-r--r--usr.sbin/XNSrouted/input.c189
-rw-r--r--usr.sbin/XNSrouted/interface.h90
-rw-r--r--usr.sbin/XNSrouted/main.c255
-rw-r--r--usr.sbin/XNSrouted/output.c147
-rw-r--r--usr.sbin/XNSrouted/protocol.h85
-rw-r--r--usr.sbin/XNSrouted/startup.c274
-rw-r--r--usr.sbin/XNSrouted/table.h99
-rw-r--r--usr.sbin/XNSrouted/tables.c319
-rw-r--r--usr.sbin/XNSrouted/timer.c139
-rw-r--r--usr.sbin/XNSrouted/tools/query.c232
-rw-r--r--usr.sbin/XNSrouted/trace.c313
-rw-r--r--usr.sbin/XNSrouted/trace.h96
-rw-r--r--usr.sbin/ac/Makefile18
-rw-r--r--usr.sbin/ac/ac.8155
-rw-r--r--usr.sbin/ac/ac.c557
-rw-r--r--usr.sbin/accton/Makefile6
-rw-r--r--usr.sbin/accton/accton.822
-rw-r--r--usr.sbin/accton/accton.c95
-rw-r--r--usr.sbin/amd/Makefile5
-rw-r--r--usr.sbin/amd/amd/ChangeLog1169
-rw-r--r--usr.sbin/amd/amd/Makefile32
-rw-r--r--usr.sbin/amd/amd/afs_ops.c1816
-rw-r--r--usr.sbin/amd/amd/am_ops.c181
-rw-r--r--usr.sbin/amd/amd/amd.8232
-rw-r--r--usr.sbin/amd/amd/amd.c344
-rw-r--r--usr.sbin/amd/amd/amq_subr.c464
-rw-r--r--usr.sbin/amd/amd/clock.c241
-rw-r--r--usr.sbin/amd/amd/efs_ops.c135
-rw-r--r--usr.sbin/amd/amd/get_args.c336
-rw-r--r--usr.sbin/amd/amd/host_ops.c681
-rw-r--r--usr.sbin/amd/amd/ifs_ops.c195
-rw-r--r--usr.sbin/amd/amd/info_file.c276
-rw-r--r--usr.sbin/amd/amd/info_hes.c697
-rw-r--r--usr.sbin/amd/amd/info_ndbm.c123
-rw-r--r--usr.sbin/amd/amd/info_nis.c247
-rw-r--r--usr.sbin/amd/amd/info_passwd.c162
-rw-r--r--usr.sbin/amd/amd/info_union.c153
-rw-r--r--usr.sbin/amd/amd/map.c1140
-rw-r--r--usr.sbin/amd/amd/mapc.c914
-rw-r--r--usr.sbin/amd/amd/misc_rpc.c333
-rw-r--r--usr.sbin/amd/amd/mntfs.c367
-rw-r--r--usr.sbin/amd/amd/mount_fs.c273
-rw-r--r--usr.sbin/amd/amd/mtab.c108
-rw-r--r--usr.sbin/amd/amd/nfs_ops.c809
-rw-r--r--usr.sbin/amd/amd/nfs_start.c435
-rw-r--r--usr.sbin/amd/amd/nfs_subr.c552
-rw-r--r--usr.sbin/amd/amd/nfsx_ops.c516
-rw-r--r--usr.sbin/amd/amd/opts.c835
-rw-r--r--usr.sbin/amd/amd/pfs_ops.c169
-rw-r--r--usr.sbin/amd/amd/restart.c181
-rw-r--r--usr.sbin/amd/amd/rpc_fwd.c430
-rw-r--r--usr.sbin/amd/amd/sched.c325
-rw-r--r--usr.sbin/amd/amd/sfs_ops.c208
-rw-r--r--usr.sbin/amd/amd/srvr_afs.c205
-rw-r--r--usr.sbin/amd/amd/srvr_nfs.c719
-rw-r--r--usr.sbin/amd/amd/ufs_ops.c178
-rw-r--r--usr.sbin/amd/amd/umount_fs.c225
-rw-r--r--usr.sbin/amd/amd/util.c648
-rw-r--r--usr.sbin/amd/amd/wire.c281
-rw-r--r--usr.sbin/amd/amd/xutil.c491
-rw-r--r--usr.sbin/amd/amq/Makefile15
-rw-r--r--usr.sbin/amd/amq/amq.8130
-rw-r--r--usr.sbin/amd/amq/amq.c666
-rw-r--r--usr.sbin/amd/config/Configure60
-rw-r--r--usr.sbin/amd/config/Makefile.aix35
-rw-r--r--usr.sbin/amd/config/Makefile.bsd448
-rw-r--r--usr.sbin/amd/config/Makefile.config91
-rw-r--r--usr.sbin/amd/config/Makefile.hpux13
-rw-r--r--usr.sbin/amd/config/Makefile.irix10
-rw-r--r--usr.sbin/amd/config/Makefile.irix313
-rw-r--r--usr.sbin/amd/config/Makefile.irix414
-rw-r--r--usr.sbin/amd/config/Makefile.stellix10
-rw-r--r--usr.sbin/amd/config/RELEASE1
-rw-r--r--usr.sbin/amd/config/arch126
-rw-r--r--usr.sbin/amd/config/misc-aix3.h96
-rw-r--r--usr.sbin/amd/config/misc-hpux.h79
-rw-r--r--usr.sbin/amd/config/misc-irix.h50
-rw-r--r--usr.sbin/amd/config/misc-next.h44
-rw-r--r--usr.sbin/amd/config/misc-stellix.h65
-rw-r--r--usr.sbin/amd/config/misc-ultrix.h55
-rw-r--r--usr.sbin/amd/config/mount_aix.c153
-rw-r--r--usr.sbin/amd/config/mount_irix.c83
-rw-r--r--usr.sbin/amd/config/mount_stellix.c76
-rw-r--r--usr.sbin/amd/config/mtab_aix.c137
-rw-r--r--usr.sbin/amd/config/mtab_bsd.c114
-rw-r--r--usr.sbin/amd/config/mtab_file.c472
-rw-r--r--usr.sbin/amd/config/mtab_ultrix.c115
-rw-r--r--usr.sbin/amd/config/newvers.sh88
-rw-r--r--usr.sbin/amd/config/os-acis43.h83
-rw-r--r--usr.sbin/amd/config/os-aix3.h181
-rw-r--r--usr.sbin/amd/config/os-aux.h117
-rw-r--r--usr.sbin/amd/config/os-bsd44.h191
-rw-r--r--usr.sbin/amd/config/os-concentrix.h79
-rw-r--r--usr.sbin/amd/config/os-convex.h80
-rw-r--r--usr.sbin/amd/config/os-defaults.h143
-rw-r--r--usr.sbin/amd/config/os-dgux.h114
-rw-r--r--usr.sbin/amd/config/os-fpx4.h92
-rw-r--r--usr.sbin/amd/config/os-hcx.h81
-rw-r--r--usr.sbin/amd/config/os-hlh42.h89
-rw-r--r--usr.sbin/amd/config/os-hpux.h150
-rw-r--r--usr.sbin/amd/config/os-irix.h133
-rw-r--r--usr.sbin/amd/config/os-irix3.h133
-rw-r--r--usr.sbin/amd/config/os-irix4.h150
-rw-r--r--usr.sbin/amd/config/os-next.h79
-rw-r--r--usr.sbin/amd/config/os-pyrOSx.h80
-rw-r--r--usr.sbin/amd/config/os-riscix.h88
-rw-r--r--usr.sbin/amd/config/os-sos3.h79
-rw-r--r--usr.sbin/amd/config/os-sos4.h116
-rw-r--r--usr.sbin/amd/config/os-stellix.h108
-rw-r--r--usr.sbin/amd/config/os-type128
-rw-r--r--usr.sbin/amd/config/os-u2_2.h161
-rw-r--r--usr.sbin/amd/config/os-u3_0.h154
-rw-r--r--usr.sbin/amd/config/os-u4_0.h158
-rw-r--r--usr.sbin/amd/config/os-u4_2.h153
-rw-r--r--usr.sbin/amd/config/os-umax43.h79
-rw-r--r--usr.sbin/amd/config/os-utek.h49
-rw-r--r--usr.sbin/amd/config/os-utx32.h85
-rw-r--r--usr.sbin/amd/config/os-xinu43.h112
-rw-r--r--usr.sbin/amd/doc/Makefile53
-rw-r--r--usr.sbin/amd/doc/amdref.cps381
-rw-r--r--usr.sbin/amd/doc/amdref.ps6429
-rw-r--r--usr.sbin/amd/doc/amdref.texinfo4554
-rw-r--r--usr.sbin/amd/doc/texinfo.tex2192
-rw-r--r--usr.sbin/amd/fsinfo/Makefile30
-rw-r--r--usr.sbin/amd/fsinfo/conf/automounts48
-rw-r--r--usr.sbin/amd/fsinfo/conf/csg_sun318
-rw-r--r--usr.sbin/amd/fsinfo/conf/csg_vax67
-rw-r--r--usr.sbin/amd/fsinfo/conf/diskless_sun3_sos49
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/achilles.doc.ic.ac.uk116
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/bigears.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/dylan.doc.ic.ac.uk68
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk104
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/ganymede.doc.ic.ac.uk33
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk477
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/gummo.doc.ic.ac.uk12
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk84
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk28
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk208
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk66
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk79
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk66
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun1.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun2.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun3.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun4.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tcsun5.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/toytown.doc.ic.ac.uk116
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/truth.doc.ic.ac.uk9
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun1.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun10.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun11.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun12.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun13.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun14.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun15.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun16.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun17.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun18.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun19.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun2.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun3.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun4.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun5.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun6.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun7.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun8.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsun9.doc.ic.ac.uk3
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk211
-rw-r--r--usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk21
-rw-r--r--usr.sbin/amd/fsinfo/conf/users106
-rw-r--r--usr.sbin/amd/fsinfo/fsi_analyze.c645
-rw-r--r--usr.sbin/amd/fsinfo/fsi_data.h236
-rw-r--r--usr.sbin/amd/fsinfo/fsi_dict.c125
-rw-r--r--usr.sbin/amd/fsinfo/fsi_gram.y394
-rw-r--r--usr.sbin/amd/fsinfo/fsi_lex.l403
-rw-r--r--usr.sbin/amd/fsinfo/fsi_util.c573
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.877
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.c275
-rw-r--r--usr.sbin/amd/fsinfo/fsinfo.h159
-rw-r--r--usr.sbin/amd/fsinfo/wr_atab.c284
-rw-r--r--usr.sbin/amd/fsinfo/wr_bparam.c101
-rw-r--r--usr.sbin/amd/fsinfo/wr_dumpset.c88
-rw-r--r--usr.sbin/amd/fsinfo/wr_exportfs.c100
-rw-r--r--usr.sbin/amd/fsinfo/wr_fstab.c303
-rw-r--r--usr.sbin/amd/include/am.h567
-rw-r--r--usr.sbin/amd/include/config.h142
-rw-r--r--usr.sbin/amd/include/fstype.h148
-rw-r--r--usr.sbin/amd/include/re.h21
-rw-r--r--usr.sbin/amd/include/remagic.h5
-rw-r--r--usr.sbin/amd/include/uwait.h83
-rw-r--r--usr.sbin/amd/maps/a_master79
-rw-r--r--usr.sbin/amd/maps/a_net3
-rw-r--r--usr.sbin/amd/mk-amd-map/Makefile11
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.859
-rw-r--r--usr.sbin/amd/mk-amd-map/mk-amd-map.c384
-rw-r--r--usr.sbin/amd/rpcx/amq.h153
-rw-r--r--usr.sbin/amd/rpcx/amq.x185
-rw-r--r--usr.sbin/amd/rpcx/amq_clnt.c181
-rw-r--r--usr.sbin/amd/rpcx/amq_svc.c136
-rw-r--r--usr.sbin/amd/rpcx/amq_xdr.c251
-rw-r--r--usr.sbin/amd/rpcx/mount.h124
-rw-r--r--usr.sbin/amd/rpcx/mount_xdr.c206
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot.h389
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_svc.c198
-rw-r--r--usr.sbin/amd/rpcx/nfs_prot_xdr.c627
-rw-r--r--usr.sbin/amd/text/COPYRIGHT3
-rw-r--r--usr.sbin/amd/text/INSTALL194
-rw-r--r--usr.sbin/amd/text/README37
-rw-r--r--usr.sbin/amd/text/amd.start.ex87
-rw-r--r--usr.sbin/arp/Makefile7
-rw-r--r--usr.sbin/arp/arp.4124
-rw-r--r--usr.sbin/arp/arp.8122
-rw-r--r--usr.sbin/arp/arp.c514
-rw-r--r--usr.sbin/arp/arp4.4124
-rw-r--r--usr.sbin/bad144/Makefile7
-rw-r--r--usr.sbin/bad144/bad144.8186
-rw-r--r--usr.sbin/bad144/bad144.c662
-rw-r--r--usr.sbin/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/Makefile15
-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.c675
-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.c500
-rw-r--r--usr.sbin/bootpd/bootptest.h30
-rw-r--r--usr.sbin/bootpd/bptypes.h23
-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.c145
-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.c294
-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/rtmsg.c236
-rw-r--r--usr.sbin/bootpd/syslog.conf63
-rw-r--r--usr.sbin/bootpd/trygetea.c46
-rw-r--r--usr.sbin/bootpd/trygetif.c68
-rw-r--r--usr.sbin/bootpd/trylook.c50
-rw-r--r--usr.sbin/bootpd/tzone.c44
-rw-r--r--usr.sbin/bootpd/tzone.h3
-rw-r--r--usr.sbin/bootpef/Makefile17
-rw-r--r--usr.sbin/bootpgw/Makefile14
-rw-r--r--usr.sbin/bootptest/Makefile15
-rw-r--r--usr.sbin/chown/Makefile9
-rw-r--r--usr.sbin/chown/chgrp.1136
-rw-r--r--usr.sbin/chown/chown.8149
-rw-r--r--usr.sbin/chown/chown.c273
-rw-r--r--usr.sbin/chroot/Makefile6
-rw-r--r--usr.sbin/chroot/chroot.879
-rw-r--r--usr.sbin/chroot/chroot.c96
-rw-r--r--usr.sbin/config.new/Makefile12
-rw-r--r--usr.sbin/config.new/config.h281
-rw-r--r--usr.sbin/config.new/config.new.8167
-rw-r--r--usr.sbin/config.new/files.c262
-rw-r--r--usr.sbin/config.new/gram.y392
-rw-r--r--usr.sbin/config.new/hash.c279
-rw-r--r--usr.sbin/config.new/main.c466
-rw-r--r--usr.sbin/config.new/mkheaders.c148
-rw-r--r--usr.sbin/config.new/mkioconf.c395
-rw-r--r--usr.sbin/config.new/mkmakefile.c364
-rw-r--r--usr.sbin/config.new/mkswap.c118
-rw-r--r--usr.sbin/config.new/pack.c520
-rw-r--r--usr.sbin/config.new/scan.l238
-rw-r--r--usr.sbin/config.new/sem.c974
-rw-r--r--usr.sbin/config.new/sem.h61
-rw-r--r--usr.sbin/config.new/util.c262
-rw-r--r--usr.sbin/config/Makefile15
-rw-r--r--usr.sbin/config/SMM.doc/0.t88
-rw-r--r--usr.sbin/config/SMM.doc/1.t61
-rw-r--r--usr.sbin/config/SMM.doc/2.t188
-rw-r--r--usr.sbin/config/SMM.doc/3.t299
-rw-r--r--usr.sbin/config/SMM.doc/4.t442
-rw-r--r--usr.sbin/config/SMM.doc/5.t271
-rw-r--r--usr.sbin/config/SMM.doc/6.t239
-rw-r--r--usr.sbin/config/SMM.doc/Makefile10
-rw-r--r--usr.sbin/config/SMM.doc/a.t162
-rw-r--r--usr.sbin/config/SMM.doc/b.t137
-rw-r--r--usr.sbin/config/SMM.doc/c.t109
-rw-r--r--usr.sbin/config/SMM.doc/d.t272
-rw-r--r--usr.sbin/config/SMM.doc/e.t114
-rw-r--r--usr.sbin/config/SMM.doc/spell.ok306
-rw-r--r--usr.sbin/config/config.8177
-rw-r--r--usr.sbin/config/config.h212
-rw-r--r--usr.sbin/config/config.y1115
-rw-r--r--usr.sbin/config/lang.l215
-rw-r--r--usr.sbin/config/main.c293
-rw-r--r--usr.sbin/config/mkglue.c397
-rw-r--r--usr.sbin/config/mkheaders.c207
-rw-r--r--usr.sbin/config/mkioconf.c1117
-rw-r--r--usr.sbin/config/mkmakefile.c636
-rw-r--r--usr.sbin/config/mkswapconf.c227
-rw-r--r--usr.sbin/config/mkubglue.c196
-rw-r--r--usr.sbin/cron/Makefile3
-rw-r--r--usr.sbin/cron/cron/Makefile18
-rw-r--r--usr.sbin/cron/cron/bitstring.3168
-rw-r--r--usr.sbin/cron/cron/bitstring.h122
-rw-r--r--usr.sbin/cron/cron/compat.h137
-rw-r--r--usr.sbin/cron/cron/config.h86
-rw-r--r--usr.sbin/cron/cron/cron.861
-rw-r--r--usr.sbin/cron/cron/cron.c301
-rw-r--r--usr.sbin/cron/cron/cron.h277
-rw-r--r--usr.sbin/cron/cron/database.c261
-rw-r--r--usr.sbin/cron/cron/do_command.c501
-rw-r--r--usr.sbin/cron/cron/externs.h145
-rw-r--r--usr.sbin/cron/cron/job.c74
-rw-r--r--usr.sbin/cron/cron/pathnames.h81
-rw-r--r--usr.sbin/cron/cron/popen.c166
-rw-r--r--usr.sbin/cron/cron/putman.sh23
-rw-r--r--usr.sbin/cron/cron/user.c102
-rw-r--r--usr.sbin/cron/crontab/Makefile19
-rw-r--r--usr.sbin/cron/crontab/crontab.1100
-rw-r--r--usr.sbin/cron/crontab/crontab.5188
-rw-r--r--usr.sbin/cron/crontab/crontab.c624
-rw-r--r--usr.sbin/cron/doc/CHANGES155
-rw-r--r--usr.sbin/cron/doc/CONVERSION85
-rw-r--r--usr.sbin/cron/doc/FEATURES84
-rw-r--r--usr.sbin/cron/doc/INSTALL87
-rw-r--r--usr.sbin/cron/doc/MAIL475
-rw-r--r--usr.sbin/cron/doc/Makefile.vixie128
-rw-r--r--usr.sbin/cron/doc/README72
-rw-r--r--usr.sbin/cron/doc/README.1ST4
-rw-r--r--usr.sbin/cron/doc/THANKS29
-rw-r--r--usr.sbin/cron/lib/Makefile11
-rw-r--r--usr.sbin/cron/lib/compat.c233
-rw-r--r--usr.sbin/cron/lib/entry.c507
-rw-r--r--usr.sbin/cron/lib/env.c178
-rw-r--r--usr.sbin/cron/lib/misc.c664
-rw-r--r--usr.sbin/crunch/COPYRIGHT25
-rw-r--r--usr.sbin/crunch/Makefile4
-rw-r--r--usr.sbin/crunch/Makefile.inc2
-rw-r--r--usr.sbin/crunch/README88
-rw-r--r--usr.sbin/crunch/crunchgen/Makefile9
-rw-r--r--usr.sbin/crunch/crunchgen/crunched_main.c102
-rw-r--r--usr.sbin/crunch/crunchgen/crunched_skel.c107
-rw-r--r--usr.sbin/crunch/crunchgen/crunchgen.1266
-rw-r--r--usr.sbin/crunch/crunchgen/crunchgen.c856
-rw-r--r--usr.sbin/crunch/crunchgen/mkskel.sh15
-rw-r--r--usr.sbin/crunch/crunchide/Makefile4
-rw-r--r--usr.sbin/crunch/crunchide/crunchide.168
-rw-r--r--usr.sbin/crunch/crunchide/crunchide.c321
-rw-r--r--usr.sbin/crunch/examples/Makefile32
-rw-r--r--usr.sbin/crunch/examples/filesystem.conf30
-rw-r--r--usr.sbin/crunch/examples/fixit.conf41
-rw-r--r--usr.sbin/crunch/examples/kcopy.conf21
-rw-r--r--usr.sbin/crunch/examples/really-big.conf146
-rw-r--r--usr.sbin/ctm/Makefile4
-rw-r--r--usr.sbin/ctm/README97
-rw-r--r--usr.sbin/ctm/ctm/Makefile19
-rw-r--r--usr.sbin/ctm/ctm/ctm.c199
-rw-r--r--usr.sbin/ctm/ctm/ctm.h132
-rw-r--r--usr.sbin/ctm/ctm/ctm_ed.c103
-rw-r--r--usr.sbin/ctm/ctm/ctm_input.c113
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass1.c182
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass2.c173
-rw-r--r--usr.sbin/ctm/ctm/ctm_pass3.c174
-rw-r--r--usr.sbin/ctm/ctm/ctm_syntax.c66
-rw-r--r--usr.sbin/ctm/ctm_scan/Makefile15
-rw-r--r--usr.sbin/ctm/ctm_scan/ctm_scan.c173
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur9
-rw-r--r--usr.sbin/ctm/mkCTM/ctm_conf.src-cur9
-rw-r--r--usr.sbin/ctm/mkCTM/mkCTM164
-rw-r--r--usr.sbin/dbsym/Makefile6
-rw-r--r--usr.sbin/dbsym/dbsym.c255
-rw-r--r--usr.sbin/dev_mkdb/Makefile6
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.881
-rw-r--r--usr.sbin/dev_mkdb/dev_mkdb.c181
-rw-r--r--usr.sbin/diskpart/Makefile6
-rw-r--r--usr.sbin/diskpart/diskpart.8143
-rw-r--r--usr.sbin/diskpart/diskpart.c474
-rw-r--r--usr.sbin/edquota/Makefile6
-rw-r--r--usr.sbin/edquota/edquota.8150
-rw-r--r--usr.sbin/edquota/edquota.c722
-rw-r--r--usr.sbin/edquota/pathnames.h39
-rw-r--r--usr.sbin/eeprom/Makefile6
-rw-r--r--usr.sbin/eeprom/eeprom.869
-rw-r--r--usr.sbin/eeprom/eeprom.c204
-rw-r--r--usr.sbin/eeprom/pathnames.h45
-rw-r--r--usr.sbin/fdformat/Makefile9
-rw-r--r--usr.sbin/fdformat/fdformat.1133
-rw-r--r--usr.sbin/fdformat/fdformat.c382
-rw-r--r--usr.sbin/fdwrite/Makefile16
-rw-r--r--usr.sbin/fdwrite/fdwrite.1117
-rw-r--r--usr.sbin/fdwrite/fdwrite.c208
-rw-r--r--usr.sbin/inetd/Makefile7
-rw-r--r--usr.sbin/inetd/inetd.8425
-rw-r--r--usr.sbin/inetd/inetd.c1405
-rw-r--r--usr.sbin/inetd/pathnames.h38
-rw-r--r--usr.sbin/iostat/Makefile11
-rw-r--r--usr.sbin/iostat/iostat.8142
-rw-r--r--usr.sbin/iostat/iostat.c391
-rw-r--r--usr.sbin/kbdcontrol/Makefile6
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.177
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.c566
-rw-r--r--usr.sbin/kbdcontrol/lex.h55
-rw-r--r--usr.sbin/kbdcontrol/lex.l114
-rw-r--r--usr.sbin/kbdcontrol/path.h4
-rw-r--r--usr.sbin/kgmon/Makefile14
-rw-r--r--usr.sbin/kgmon/kgmon.8122
-rw-r--r--usr.sbin/kgmon/kgmon.c520
-rw-r--r--usr.sbin/kvm_mkdb/Makefile7
-rw-r--r--usr.sbin/kvm_mkdb/extern.h38
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.869
-rw-r--r--usr.sbin/kvm_mkdb/kvm_mkdb.c111
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c200
-rw-r--r--usr.sbin/kvm_mkdb/testdb.c113
-rw-r--r--usr.sbin/lpr/Makefile6
-rw-r--r--usr.sbin/lpr/SMM.doc/0.t68
-rw-r--r--usr.sbin/lpr/SMM.doc/1.t77
-rw-r--r--usr.sbin/lpr/SMM.doc/2.t141
-rw-r--r--usr.sbin/lpr/SMM.doc/3.t73
-rw-r--r--usr.sbin/lpr/SMM.doc/4.t206
-rw-r--r--usr.sbin/lpr/SMM.doc/5.t116
-rw-r--r--usr.sbin/lpr/SMM.doc/6.t94
-rw-r--r--usr.sbin/lpr/SMM.doc/7.t226
-rw-r--r--usr.sbin/lpr/SMM.doc/Makefile10
-rw-r--r--usr.sbin/lpr/SMM.doc/spell.ok70
-rw-r--r--usr.sbin/lpr/common_source/common.c352
-rw-r--r--usr.sbin/lpr/common_source/displayq.c449
-rw-r--r--usr.sbin/lpr/common_source/lp.h126
-rw-r--r--usr.sbin/lpr/common_source/lp.local.h80
-rw-r--r--usr.sbin/lpr/common_source/pathnames.h50
-rw-r--r--usr.sbin/lpr/common_source/printcap.c458
-rw-r--r--usr.sbin/lpr/common_source/recvjob.c358
-rw-r--r--usr.sbin/lpr/common_source/rmjob.c339
-rw-r--r--usr.sbin/lpr/common_source/startdaemon.c108
-rw-r--r--usr.sbin/lpr/filters/Makefile7
-rw-r--r--usr.sbin/lpr/filters/lpf.c217
-rw-r--r--usr.sbin/lpr/lpc/Makefile12
-rw-r--r--usr.sbin/lpr/lpc/cmds.c1107
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c79
-rw-r--r--usr.sbin/lpr/lpc/extern.h58
-rw-r--r--usr.sbin/lpr/lpc/lpc.8174
-rw-r--r--usr.sbin/lpr/lpc/lpc.c277
-rw-r--r--usr.sbin/lpr/lpc/lpc.h45
-rw-r--r--usr.sbin/lpr/lpd/Makefile11
-rw-r--r--usr.sbin/lpr/lpd/extern.h39
-rw-r--r--usr.sbin/lpr/lpd/lpd.8249
-rw-r--r--usr.sbin/lpr/lpd/lpd.c507
-rw-r--r--usr.sbin/lpr/lpd/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/lpd/printjob.c1377
-rw-r--r--usr.sbin/lpr/lpd/recvjob.c358
-rw-r--r--usr.sbin/lpr/lpq/Makefile13
-rw-r--r--usr.sbin/lpr/lpq/lpq.1134
-rw-r--r--usr.sbin/lpr/lpq/lpq.c126
-rw-r--r--usr.sbin/lpr/lpr/Makefile13
-rw-r--r--usr.sbin/lpr/lpr/lpr.1256
-rw-r--r--usr.sbin/lpr/lpr/lpr.c744
-rw-r--r--usr.sbin/lpr/lpr/printcap.5288
-rw-r--r--usr.sbin/lpr/lprm/Makefile13
-rw-r--r--usr.sbin/lpr/lprm/lprm.1145
-rw-r--r--usr.sbin/lpr/lprm/lprm.c144
-rw-r--r--usr.sbin/lpr/lptest/Makefile7
-rw-r--r--usr.sbin/lpr/lptest/lptest.174
-rw-r--r--usr.sbin/lpr/lptest/lptest.c83
-rw-r--r--usr.sbin/lpr/pac/Makefile10
-rw-r--r--usr.sbin/lpr/pac/pac.8106
-rw-r--r--usr.sbin/lpr/pac/pac.c444
-rw-r--r--usr.sbin/lpr/runqueue/extern.h39
-rw-r--r--usr.sbin/lpr/runqueue/lpdchar.c1066
-rw-r--r--usr.sbin/lpr/runqueue/printjob.c1377
-rw-r--r--usr.sbin/lptcontrol/Makefile5
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.873
-rw-r--r--usr.sbin/lptcontrol/lptcontrol.c113
-rw-r--r--usr.sbin/manctl/Makefile11
-rw-r--r--usr.sbin/manctl/manctl.sh376
-rw-r--r--usr.sbin/mount_portalfs/Makefile15
-rw-r--r--usr.sbin/mount_portalfs/activate.c215
-rw-r--r--usr.sbin/mount_portalfs/conf.c329
-rw-r--r--usr.sbin/mount_portalfs/mount_portalfs.8136
-rw-r--r--usr.sbin/mount_portalfs/mount_portalfs.c270
-rw-r--r--usr.sbin/mount_portalfs/pathnames.h44
-rw-r--r--usr.sbin/mount_portalfs/portal.conf7
-rw-r--r--usr.sbin/mount_portalfs/portald.h82
-rw-r--r--usr.sbin/mount_portalfs/pt_conf.c51
-rw-r--r--usr.sbin/mount_portalfs/pt_exec.c61
-rw-r--r--usr.sbin/mount_portalfs/pt_file.c106
-rw-r--r--usr.sbin/mount_portalfs/pt_tcp.c158
-rw-r--r--usr.sbin/mountd/Makefile9
-rw-r--r--usr.sbin/mountd/exports.5250
-rw-r--r--usr.sbin/mountd/mountd.8118
-rw-r--r--usr.sbin/mountd/mountd.c2020
-rw-r--r--usr.sbin/mountd/netgroup.591
-rw-r--r--usr.sbin/mountd/pathnames.h39
-rw-r--r--usr.sbin/mrouted/LICENSE48
-rw-r--r--usr.sbin/mrouted/Makefile5
-rw-r--r--usr.sbin/mrouted/Makefile.inc1
-rw-r--r--usr.sbin/mrouted/callout.c201
-rw-r--r--usr.sbin/mrouted/common/Makefile17
-rw-r--r--usr.sbin/mrouted/config.c796
-rw-r--r--usr.sbin/mrouted/defs.h172
-rw-r--r--usr.sbin/mrouted/dvmrp.h152
-rw-r--r--usr.sbin/mrouted/igmp.c291
-rw-r--r--usr.sbin/mrouted/inet.c187
-rw-r--r--usr.sbin/mrouted/kern.c183
-rw-r--r--usr.sbin/mrouted/main.c439
-rw-r--r--usr.sbin/mrouted/map-mbone/Makefile20
-rw-r--r--usr.sbin/mrouted/mapper.c954
-rw-r--r--usr.sbin/mrouted/mrinfo.c481
-rw-r--r--usr.sbin/mrouted/mrinfo/Makefile20
-rw-r--r--usr.sbin/mrouted/mrouted.8319
-rw-r--r--usr.sbin/mrouted/mrouted.conf26
-rw-r--r--usr.sbin/mrouted/mrouted/Makefile20
-rw-r--r--usr.sbin/mrouted/mtrace.c460
-rw-r--r--usr.sbin/mrouted/mtrace/Makefile20
-rw-r--r--usr.sbin/mrouted/prune.c1370
-rw-r--r--usr.sbin/mrouted/prune.h123
-rw-r--r--usr.sbin/mrouted/route.c1076
-rw-r--r--usr.sbin/mrouted/route.h50
-rw-r--r--usr.sbin/mrouted/vif.c1138
-rw-r--r--usr.sbin/mrouted/vif.h62
-rw-r--r--usr.sbin/mtree/Makefile8
-rw-r--r--usr.sbin/mtree/compare.c271
-rw-r--r--usr.sbin/mtree/create.c333
-rw-r--r--usr.sbin/mtree/extern.h44
-rw-r--r--usr.sbin/mtree/misc.c126
-rw-r--r--usr.sbin/mtree/mtree.8263
-rw-r--r--usr.sbin/mtree/mtree.c152
-rw-r--r--usr.sbin/mtree/mtree.h88
-rw-r--r--usr.sbin/mtree/spec.c280
-rw-r--r--usr.sbin/mtree/verify.c203
-rw-r--r--usr.sbin/named/Makefile80
-rw-r--r--usr.sbin/named/Version.c88
-rw-r--r--usr.sbin/named/db_defs.h172
-rw-r--r--usr.sbin/named/db_dump.c897
-rw-r--r--usr.sbin/named/db_func.h102
-rw-r--r--usr.sbin/named/db_glob.h93
-rw-r--r--usr.sbin/named/db_glue.c710
-rw-r--r--usr.sbin/named/db_load.c1218
-rw-r--r--usr.sbin/named/db_lookup.c196
-rw-r--r--usr.sbin/named/db_reload.c125
-rw-r--r--usr.sbin/named/db_save.c214
-rw-r--r--usr.sbin/named/db_secure.c170
-rw-r--r--usr.sbin/named/db_update.c638
-rw-r--r--usr.sbin/named/dmalloc.c310
-rw-r--r--usr.sbin/named/dmalloc.h68
-rw-r--r--usr.sbin/named/named.8378
-rw-r--r--usr.sbin/named/named.h19
-rw-r--r--usr.sbin/named/ns_defs.h368
-rw-r--r--usr.sbin/named/ns_forw.c909
-rw-r--r--usr.sbin/named/ns_func.h140
-rw-r--r--usr.sbin/named/ns_glob.h245
-rw-r--r--usr.sbin/named/ns_init.c808
-rw-r--r--usr.sbin/named/ns_main.c1581
-rw-r--r--usr.sbin/named/ns_maint.c784
-rw-r--r--usr.sbin/named/ns_ncache.c152
-rw-r--r--usr.sbin/named/ns_req.c1793
-rw-r--r--usr.sbin/named/ns_resp.c2190
-rw-r--r--usr.sbin/named/ns_sort.c169
-rw-r--r--usr.sbin/named/ns_stats.c325
-rw-r--r--usr.sbin/named/ns_validate.c1161
-rw-r--r--usr.sbin/named/options.h160
-rw-r--r--usr.sbin/named/pathnames.h122
-rw-r--r--usr.sbin/named/portability.h456
-rw-r--r--usr.sbin/named/storage.c205
-rw-r--r--usr.sbin/named/tools/Makefile5
-rw-r--r--usr.sbin/named/tools/named.reload/Makefile18
-rw-r--r--usr.sbin/named/tools/named.reload/named.reload.869
-rw-r--r--usr.sbin/named/tools/named.reload/named.reload.sh6
-rw-r--r--usr.sbin/named/tools/named.restart/Makefile20
-rw-r--r--usr.sbin/named/tools/named.restart/named.restart.873
-rw-r--r--usr.sbin/named/tools/named.restart/named.restart.sh12
-rw-r--r--usr.sbin/named/tools/nsquery/Makefile7
-rw-r--r--usr.sbin/named/tools/nsquery/nsquery.c140
-rw-r--r--usr.sbin/named/tools/nstest/Makefile7
-rw-r--r--usr.sbin/named/tools/nstest/nstest.c423
-rw-r--r--usr.sbin/named/tree.c570
-rw-r--r--usr.sbin/named/tree.h48
-rw-r--r--usr.sbin/named/tree.man3154
-rw-r--r--usr.sbin/named/xfer/Makefile11
-rw-r--r--usr.sbin/named/xfer/named-xfer.8146
-rw-r--r--usr.sbin/named/xfer/named-xfer.c1487
-rw-r--r--usr.sbin/nfsd/Makefile7
-rw-r--r--usr.sbin/nfsd/nfsd.8132
-rw-r--r--usr.sbin/nfsd/nfsd.c601
-rw-r--r--usr.sbin/nologin/Makefile11
-rw-r--r--usr.sbin/nologin/nologin.854
-rw-r--r--usr.sbin/nologin/nologin.sh38
-rw-r--r--usr.sbin/nslookup/Makefile14
-rw-r--r--usr.sbin/nslookup/commands.l219
-rw-r--r--usr.sbin/nslookup/debug.c541
-rw-r--r--usr.sbin/nslookup/getinfo.c827
-rw-r--r--usr.sbin/nslookup/list.c997
-rw-r--r--usr.sbin/nslookup/main.c1112
-rw-r--r--usr.sbin/nslookup/nslookup.8387
-rw-r--r--usr.sbin/nslookup/nslookup.help33
-rw-r--r--usr.sbin/nslookup/pathnames.h66
-rw-r--r--usr.sbin/nslookup/res.h172
-rw-r--r--usr.sbin/nslookup/send.c411
-rw-r--r--usr.sbin/nslookup/skip.c210
-rw-r--r--usr.sbin/nslookup/subr.c559
-rw-r--r--usr.sbin/pkg_install/+COMMENT1
-rw-r--r--usr.sbin/pkg_install/+CONTENTS2
-rw-r--r--usr.sbin/pkg_install/+DESC5
-rw-r--r--usr.sbin/pkg_install/Makefile3
-rw-r--r--usr.sbin/pkg_install/Makefile.inc2
-rw-r--r--usr.sbin/pkg_install/README5
-rw-r--r--usr.sbin/pkg_install/add/Makefile9
-rw-r--r--usr.sbin/pkg_install/add/add.h43
-rw-r--r--usr.sbin/pkg_install/add/extract.c108
-rw-r--r--usr.sbin/pkg_install/add/futil.c86
-rw-r--r--usr.sbin/pkg_install/add/main.c140
-rw-r--r--usr.sbin/pkg_install/add/perform.c235
-rw-r--r--usr.sbin/pkg_install/add/pkg_add.1203
-rw-r--r--usr.sbin/pkg_install/create/Makefile9
-rw-r--r--usr.sbin/pkg_install/create/create.h42
-rw-r--r--usr.sbin/pkg_install/create/main.c150
-rw-r--r--usr.sbin/pkg_install/create/perform.c181
-rw-r--r--usr.sbin/pkg_install/create/pkg_create.1280
-rw-r--r--usr.sbin/pkg_install/create/pl.c111
-rw-r--r--usr.sbin/pkg_install/delete/Makefile9
-rw-r--r--usr.sbin/pkg_install/delete/delete.h31
-rw-r--r--usr.sbin/pkg_install/delete/main.c108
-rw-r--r--usr.sbin/pkg_install/delete/perform.c122
-rw-r--r--usr.sbin/pkg_install/delete/pkg_delete.1124
-rw-r--r--usr.sbin/pkg_install/info/Makefile9
-rw-r--r--usr.sbin/pkg_install/info/info.h47
-rw-r--r--usr.sbin/pkg_install/info/main.c165
-rw-r--r--usr.sbin/pkg_install/info/perform.c156
-rw-r--r--usr.sbin/pkg_install/info/pkg_info.1123
-rw-r--r--usr.sbin/pkg_install/info/show.c145
-rw-r--r--usr.sbin/pkg_install/lib/Makefile9
-rw-r--r--usr.sbin/pkg_install/lib/exec.c48
-rw-r--r--usr.sbin/pkg_install/lib/file.c232
-rw-r--r--usr.sbin/pkg_install/lib/global.c33
-rw-r--r--usr.sbin/pkg_install/lib/lib.h155
-rw-r--r--usr.sbin/pkg_install/lib/msg.c103
-rw-r--r--usr.sbin/pkg_install/lib/pen.c74
-rw-r--r--usr.sbin/pkg_install/lib/plist.c366
-rw-r--r--usr.sbin/pkg_install/lib/str.c85
-rwxr-xr-xusr.sbin/pkg_install/pkg158
-rwxr-xr-xusr.sbin/pkg_install/tkpkg161
-rw-r--r--usr.sbin/portmap/Makefile11
-rw-r--r--usr.sbin/portmap/from_local.c147
-rw-r--r--usr.sbin/portmap/pmap_check.c251
-rw-r--r--usr.sbin/portmap/pmap_check.h11
-rw-r--r--usr.sbin/portmap/pmap_dump/Makefile7
-rw-r--r--usr.sbin/portmap/pmap_dump/pmap_dump.c63
-rw-r--r--usr.sbin/portmap/pmap_set/Makefile7
-rw-r--r--usr.sbin/portmap/pmap_set/pmap_set.c70
-rw-r--r--usr.sbin/portmap/portmap.8112
-rw-r--r--usr.sbin/portmap/portmap.c599
-rw-r--r--usr.sbin/pppd/Makefile14
-rw-r--r--usr.sbin/pppd/RELNOTES295
-rw-r--r--usr.sbin/pppd/args.h12
-rw-r--r--usr.sbin/pppd/auth.c904
-rw-r--r--usr.sbin/pppd/callout.h18
-rw-r--r--usr.sbin/pppd/chap.c823
-rw-r--r--usr.sbin/pppd/chap.h112
-rw-r--r--usr.sbin/pppd/fsm.c773
-rw-r--r--usr.sbin/pppd/fsm.h127
-rw-r--r--usr.sbin/pppd/ipcp.c1196
-rw-r--r--usr.sbin/pppd/ipcp.h68
-rw-r--r--usr.sbin/pppd/lcp.c1644
-rw-r--r--usr.sbin/pppd/lcp.h87
-rw-r--r--usr.sbin/pppd/lock.c122
-rw-r--r--usr.sbin/pppd/magic.c70
-rw-r--r--usr.sbin/pppd/magic.h24
-rw-r--r--usr.sbin/pppd/main.c1445
-rw-r--r--usr.sbin/pppd/md5.c304
-rw-r--r--usr.sbin/pppd/md5.h58
-rw-r--r--usr.sbin/pppd/options.c1454
-rw-r--r--usr.sbin/pppd/patchlevel.h5
-rw-r--r--usr.sbin/pppd/pathnames.h19
-rw-r--r--usr.sbin/pppd/ppp.h41
-rw-r--r--usr.sbin/pppd/pppd.8701
-rw-r--r--usr.sbin/pppd/pppd.h215
-rw-r--r--usr.sbin/pppd/sys-bsd.c743
-rw-r--r--usr.sbin/pppd/sys-linux.c830
-rw-r--r--usr.sbin/pppd/sys-str.c730
-rw-r--r--usr.sbin/pppd/sys-ultrix.c663
-rw-r--r--usr.sbin/pppd/upap.c561
-rw-r--r--usr.sbin/pppd/upap.h91
-rw-r--r--usr.sbin/pstat/Makefile11
-rw-r--r--usr.sbin/pstat/pstat.8321
-rw-r--r--usr.sbin/pstat/pstat.c1110
-rw-r--r--usr.sbin/pwd_mkdb/Makefile7
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.c139
-rw-r--r--usr.sbin/pwd_mkdb/pw_scan.h36
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.8132
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c427
-rw-r--r--usr.sbin/quot/quot.884
-rw-r--r--usr.sbin/quotaon/Makefile8
-rw-r--r--usr.sbin/quotaon/quotaon.8139
-rw-r--r--usr.sbin/quotaon/quotaon.c251
-rw-r--r--usr.sbin/repquota/Makefile6
-rw-r--r--usr.sbin/repquota/repquota.8103
-rw-r--r--usr.sbin/repquota/repquota.c379
-rw-r--r--usr.sbin/rmt/Makefile6
-rw-r--r--usr.sbin/rmt/rmt.8217
-rw-r--r--usr.sbin/rmt/rmt.c244
-rw-r--r--usr.sbin/routed/Makefile22
-rw-r--r--usr.sbin/routed/af.c171
-rw-r--r--usr.sbin/routed/af.h65
-rw-r--r--usr.sbin/routed/defs.h103
-rw-r--r--usr.sbin/routed/if.c148
-rw-r--r--usr.sbin/routed/inet.c243
-rw-r--r--usr.sbin/routed/input.c362
-rw-r--r--usr.sbin/routed/interface.h90
-rw-r--r--usr.sbin/routed/main.c351
-rw-r--r--usr.sbin/routed/output.c172
-rw-r--r--usr.sbin/routed/pathnames.h38
-rw-r--r--usr.sbin/routed/query/Makefile7
-rw-r--r--usr.sbin/routed/query/query.c294
-rw-r--r--usr.sbin/routed/routed.8358
-rw-r--r--usr.sbin/routed/startup.c515
-rw-r--r--usr.sbin/routed/table.h108
-rw-r--r--usr.sbin/routed/tables.c428
-rw-r--r--usr.sbin/routed/timer.c127
-rw-r--r--usr.sbin/routed/trace.c426
-rw-r--r--usr.sbin/routed/trace.h96
-rw-r--r--usr.sbin/routed/trace/Makefile7
-rw-r--r--usr.sbin/routed/trace/trace.c125
-rw-r--r--usr.sbin/rtprio/Makefile7
-rw-r--r--usr.sbin/rtprio/rtprio.1165
-rw-r--r--usr.sbin/rtprio/rtprio.c141
-rw-r--r--usr.sbin/rwhod/Makefile6
-rw-r--r--usr.sbin/rwhod/rwhod.8146
-rw-r--r--usr.sbin/rwhod/rwhod.c539
-rw-r--r--usr.sbin/sa/Makefile7
-rw-r--r--usr.sbin/sa/extern.h100
-rw-r--r--usr.sbin/sa/main.c542
-rw-r--r--usr.sbin/sa/pathnames.h35
-rw-r--r--usr.sbin/sa/pdb.c418
-rw-r--r--usr.sbin/sa/sa.8240
-rw-r--r--usr.sbin/sa/usrdb.c282
-rw-r--r--usr.sbin/sendmail/FAQ343
-rw-r--r--usr.sbin/sendmail/KNOWNBUGS131
-rw-r--r--usr.sbin/sendmail/Makefile24
-rw-r--r--usr.sbin/sendmail/READ_ME239
-rw-r--r--usr.sbin/sendmail/RELEASE_NOTES2556
-rw-r--r--usr.sbin/sendmail/cf/README1232
-rw-r--r--usr.sbin/sendmail/cf/cf/Makefile86
-rw-r--r--usr.sbin/sendmail/cf/cf/Makefile.dist85
-rw-r--r--usr.sbin/sendmail/cf/cf/alpha.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/auspex.mc42
-rw-r--r--usr.sbin/sendmail/cf/cf/chez.mc44
-rw-r--r--usr.sbin/sendmail/cf/cf/clientproto.mc49
-rw-r--r--usr.sbin/sendmail/cf/cf/cogsci.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/cs-exposed.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/cs-hidden.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/freefall.mc47
-rw-r--r--usr.sbin/sendmail/cf/cf/hpux-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/hpux-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/knecht.mc44
-rw-r--r--usr.sbin/sendmail/cf/cf/mail.cs.mc55
-rw-r--r--usr.sbin/sendmail/cf/cf/mail.eecs.mc54
-rw-r--r--usr.sbin/sendmail/cf/cf/osf1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/osf1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/python.mc52
-rw-r--r--usr.sbin/sendmail/cf/cf/riscos-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/s2k.mc42
-rw-r--r--usr.sbin/sendmail/cf/cf/sample.mc40
-rw-r--r--usr.sbin/sendmail/cf/cf/sleepy.mc43
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos3.5-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos3.5-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos4.1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/sunos4.1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/tcpproto.mc50
-rw-r--r--usr.sbin/sendmail/cf/cf/ucbarpa.mc43
-rw-r--r--usr.sbin/sendmail/cf/cf/ucbvax.mc101
-rw-r--r--usr.sbin/sendmail/cf/cf/udb.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/ultrix4.1-cs-exposed.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/ultrix4.1-cs-hidden.mc41
-rw-r--r--usr.sbin/sendmail/cf/cf/uucpproto.mc49
-rw-r--r--usr.sbin/sendmail/cf/cf/vangogh.mc44
-rw-r--r--usr.sbin/sendmail/cf/domain/Berkeley.m442
-rw-r--r--usr.sbin/sendmail/cf/domain/cs.exposed.m440
-rw-r--r--usr.sbin/sendmail/cf/domain/cs.hidden.m438
-rw-r--r--usr.sbin/sendmail/cf/domain/eecs.hidden.m438
-rw-r--r--usr.sbin/sendmail/cf/domain/s2k.m438
-rw-r--r--usr.sbin/sendmail/cf/feature/allmasquerade.m441
-rw-r--r--usr.sbin/sendmail/cf/feature/always_add_domain.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/bitdomain.m449
-rw-r--r--usr.sbin/sendmail/cf/feature/domaintable.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/mailertable.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nocanonify.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nodns.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/notsticky.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nouucp.m440
-rw-r--r--usr.sbin/sendmail/cf/feature/nullclient.m461
-rw-r--r--usr.sbin/sendmail/cf/feature/redirect.m448
-rw-r--r--usr.sbin/sendmail/cf/feature/use_cw_file.m446
-rw-r--r--usr.sbin/sendmail/cf/feature/uucpdomain.m449
-rw-r--r--usr.sbin/sendmail/cf/hack/cssubdomain.m444
-rw-r--r--usr.sbin/sendmail/cf/m4/cf.m4149
-rw-r--r--usr.sbin/sendmail/cf/m4/nullrelay.m4302
-rw-r--r--usr.sbin/sendmail/cf/m4/proto.m4689
-rw-r--r--usr.sbin/sendmail/cf/m4/version.m439
-rw-r--r--usr.sbin/sendmail/cf/mailer/fax.m450
-rw-r--r--usr.sbin/sendmail/cf/mailer/local.m466
-rw-r--r--usr.sbin/sendmail/cf/mailer/pop.m453
-rw-r--r--usr.sbin/sendmail/cf/mailer/smtp.m4126
-rw-r--r--usr.sbin/sendmail/cf/mailer/usenet.m447
-rw-r--r--usr.sbin/sendmail/cf/mailer/uucp.m4172
-rw-r--r--usr.sbin/sendmail/cf/ostype/aix3.m440
-rw-r--r--usr.sbin/sendmail/cf/ostype/aux.m443
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsd4.3.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsd4.4.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/bsdi1.0.m438
-rw-r--r--usr.sbin/sendmail/cf/ostype/dgux.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/domainos.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/dynix3.2.m439
-rw-r--r--usr.sbin/sendmail/cf/ostype/hpux.m444
-rw-r--r--usr.sbin/sendmail/cf/ostype/irix.m441
-rw-r--r--usr.sbin/sendmail/cf/ostype/linux.m438
-rw-r--r--usr.sbin/sendmail/cf/ostype/nextstep.m444
-rw-r--r--usr.sbin/sendmail/cf/ostype/osf1.m441
-rw-r--r--usr.sbin/sendmail/cf/ostype/riscos4.5.m442
-rw-r--r--usr.sbin/sendmail/cf/ostype/sco3.2.m445
-rw-r--r--usr.sbin/sendmail/cf/ostype/solaris2.m443
-rw-r--r--usr.sbin/sendmail/cf/ostype/sunos3.5.m437
-rw-r--r--usr.sbin/sendmail/cf/ostype/sunos4.1.m437
-rw-r--r--usr.sbin/sendmail/cf/ostype/svr4.m445
-rw-r--r--usr.sbin/sendmail/cf/ostype/ultrix4.1.m438
-rw-r--r--usr.sbin/sendmail/cf/sh/makeinfo.sh77
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.cogsci.m46
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.old.arpa.m44
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.ucbarpa.m41
-rw-r--r--usr.sbin/sendmail/cf/siteconfig/uucp.ucbvax.m473
-rw-r--r--usr.sbin/sendmail/contrib/README10
-rw-r--r--usr.sbin/sendmail/contrib/bitdomain.c409
-rw-r--r--usr.sbin/sendmail/contrib/converting.sun.configs446
-rwxr-xr-xusr.sbin/sendmail/contrib/expn.pl1365
-rw-r--r--usr.sbin/sendmail/contrib/mail.local.linux205
-rw-r--r--usr.sbin/sendmail/contrib/mh.patch193
-rw-r--r--usr.sbin/sendmail/contrib/mmuegel2079
-rw-r--r--usr.sbin/sendmail/contrib/oldbind.compat.c79
-rw-r--r--usr.sbin/sendmail/contrib/rcpt-streaming305
-rw-r--r--usr.sbin/sendmail/contrib/xla/README207
-rw-r--r--usr.sbin/sendmail/contrib/xla/xla.c532
-rw-r--r--usr.sbin/sendmail/doc/Makefile5
-rw-r--r--usr.sbin/sendmail/doc/changes/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/changes/changes.me997
-rw-r--r--usr.sbin/sendmail/doc/changes/changes.ps1088
-rw-r--r--usr.sbin/sendmail/doc/intro/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/intro/intro.me1478
-rw-r--r--usr.sbin/sendmail/doc/intro/intro.ps1295
-rw-r--r--usr.sbin/sendmail/doc/op/Makefile13
-rw-r--r--usr.sbin/sendmail/doc/op/op.me6921
-rw-r--r--usr.sbin/sendmail/doc/op/op.ps5477
-rw-r--r--usr.sbin/sendmail/doc/op/spell.ok324
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc819.txt1044
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc821.txt4050
-rw-r--r--usr.sbin/sendmail/doc/rfc/rfc822.txt2901
-rw-r--r--usr.sbin/sendmail/doc/usenix/Makefile12
-rw-r--r--usr.sbin/sendmail/doc/usenix/usenix.me1076
-rw-r--r--usr.sbin/sendmail/doc/usenix/usenix.ps1004
-rw-r--r--usr.sbin/sendmail/mailstats/Makefile8
-rw-r--r--usr.sbin/sendmail/mailstats/mailstats.c209
-rw-r--r--usr.sbin/sendmail/makemap/Makefile8
-rw-r--r--usr.sbin/sendmail/makemap/Makefile.dist81
-rw-r--r--usr.sbin/sendmail/makemap/makemap.8128
-rw-r--r--usr.sbin/sendmail/makemap/makemap.c373
-rw-r--r--usr.sbin/sendmail/praliases/Makefile9
-rw-r--r--usr.sbin/sendmail/praliases/Makefile.dist81
-rw-r--r--usr.sbin/sendmail/praliases/praliases.c132
-rw-r--r--usr.sbin/sendmail/src/Makefile42
-rw-r--r--usr.sbin/sendmail/src/Makefile.386BSD42
-rw-r--r--usr.sbin/sendmail/src/Makefile.AIX113
-rw-r--r--usr.sbin/sendmail/src/Makefile.AUX105
-rw-r--r--usr.sbin/sendmail/src/Makefile.BSD43123
-rw-r--r--usr.sbin/sendmail/src/Makefile.BSDI32
-rw-r--r--usr.sbin/sendmail/src/Makefile.CLIX115
-rw-r--r--usr.sbin/sendmail/src/Makefile.ConvexOS105
-rw-r--r--usr.sbin/sendmail/src/Makefile.DGUX101
-rw-r--r--usr.sbin/sendmail/src/Makefile.Dell113
-rw-r--r--usr.sbin/sendmail/src/Makefile.DomainOS123
-rw-r--r--usr.sbin/sendmail/src/Makefile.Dynix113
-rw-r--r--usr.sbin/sendmail/src/Makefile.FreeBSD50
-rw-r--r--usr.sbin/sendmail/src/Makefile.HP-UX105
-rw-r--r--usr.sbin/sendmail/src/Makefile.IRIX109
-rw-r--r--usr.sbin/sendmail/src/Makefile.Linux120
-rw-r--r--usr.sbin/sendmail/src/Makefile.Mach386107
-rw-r--r--usr.sbin/sendmail/src/Makefile.NCR3000109
-rw-r--r--usr.sbin/sendmail/src/Makefile.NeXT114
-rw-r--r--usr.sbin/sendmail/src/Makefile.NetBSD46
-rw-r--r--usr.sbin/sendmail/src/Makefile.OSF1109
-rw-r--r--usr.sbin/sendmail/src/Makefile.PTX114
-rw-r--r--usr.sbin/sendmail/src/Makefile.RISCos117
-rw-r--r--usr.sbin/sendmail/src/Makefile.SCO104
-rw-r--r--usr.sbin/sendmail/src/Makefile.SVR4113
-rw-r--r--usr.sbin/sendmail/src/Makefile.Solaris115
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS111
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS.4.0.3113
-rw-r--r--usr.sbin/sendmail/src/Makefile.SunOS.5.x115
-rw-r--r--usr.sbin/sendmail/src/Makefile.Titan114
-rw-r--r--usr.sbin/sendmail/src/Makefile.ULTRIX107
-rw-r--r--usr.sbin/sendmail/src/Makefile.UMAX114
-rw-r--r--usr.sbin/sendmail/src/Makefile.Utah40
-rw-r--r--usr.sbin/sendmail/src/Makefile.dist107
-rw-r--r--usr.sbin/sendmail/src/READ_ME872
-rw-r--r--usr.sbin/sendmail/src/TODO287
-rw-r--r--usr.sbin/sendmail/src/TRACEFLAGS64
-rw-r--r--usr.sbin/sendmail/src/alias.c770
-rw-r--r--usr.sbin/sendmail/src/aliases.5106
-rw-r--r--usr.sbin/sendmail/src/arpadate.c173
-rw-r--r--usr.sbin/sendmail/src/clock.c276
-rw-r--r--usr.sbin/sendmail/src/collect.c579
-rw-r--r--usr.sbin/sendmail/src/conf.c2381
-rw-r--r--usr.sbin/sendmail/src/conf.h1191
-rw-r--r--usr.sbin/sendmail/src/convtime.c197
-rw-r--r--usr.sbin/sendmail/src/daemon.c1547
-rw-r--r--usr.sbin/sendmail/src/deliver.c2409
-rw-r--r--usr.sbin/sendmail/src/domain.c769
-rw-r--r--usr.sbin/sendmail/src/envelope.c777
-rw-r--r--usr.sbin/sendmail/src/err.c561
-rw-r--r--usr.sbin/sendmail/src/headers.c1192
-rw-r--r--usr.sbin/sendmail/src/macro.c279
-rw-r--r--usr.sbin/sendmail/src/mailq.188
-rw-r--r--usr.sbin/sendmail/src/mailstats.h49
-rw-r--r--usr.sbin/sendmail/src/main.c1479
-rw-r--r--usr.sbin/sendmail/src/makesendmail113
-rw-r--r--usr.sbin/sendmail/src/map.c1339
-rw-r--r--usr.sbin/sendmail/src/mci.c398
-rw-r--r--usr.sbin/sendmail/src/newaliases.168
-rw-r--r--usr.sbin/sendmail/src/parseaddr.c1964
-rw-r--r--usr.sbin/sendmail/src/pathnames.h46
-rw-r--r--usr.sbin/sendmail/src/queue.c1571
-rw-r--r--usr.sbin/sendmail/src/readcf.c1681
-rw-r--r--usr.sbin/sendmail/src/recipient.c1059
-rw-r--r--usr.sbin/sendmail/src/savemail.c833
-rw-r--r--usr.sbin/sendmail/src/sendmail.8501
-rw-r--r--usr.sbin/sendmail/src/sendmail.h973
-rw-r--r--usr.sbin/sendmail/src/sendmail.hf58
-rw-r--r--usr.sbin/sendmail/src/srvrsmtp.c1032
-rw-r--r--usr.sbin/sendmail/src/stab.c166
-rw-r--r--usr.sbin/sendmail/src/stats.c130
-rw-r--r--usr.sbin/sendmail/src/sysexits.c67
-rw-r--r--usr.sbin/sendmail/src/trace.c131
-rw-r--r--usr.sbin/sendmail/src/udb.c985
-rw-r--r--usr.sbin/sendmail/src/useful.h77
-rw-r--r--usr.sbin/sendmail/src/usersmtp.c905
-rw-r--r--usr.sbin/sendmail/src/util.c1467
-rw-r--r--usr.sbin/sendmail/src/version.c39
-rw-r--r--usr.sbin/sliplogin/Makefile9
-rw-r--r--usr.sbin/sliplogin/pathnames.h46
-rw-r--r--usr.sbin/sliplogin/slip.hosts11
-rw-r--r--usr.sbin/sliplogin/slip.login12
-rw-r--r--usr.sbin/sliplogin/sliplogin.8220
-rw-r--r--usr.sbin/sliplogin/sliplogin.c384
-rw-r--r--usr.sbin/slstat/Makefile11
-rw-r--r--usr.sbin/slstat/slstat.8141
-rw-r--r--usr.sbin/slstat/slstat.c287
-rw-r--r--usr.sbin/swapinfo/Makefile12
-rw-r--r--usr.sbin/swapinfo/README38
-rw-r--r--usr.sbin/swapinfo/devname.c75
-rw-r--r--usr.sbin/swapinfo/swapinfo.153
-rw-r--r--usr.sbin/swapinfo/swapinfo.c225
-rw-r--r--usr.sbin/sysctl/Makefile6
-rw-r--r--usr.sbin/sysctl/pathconf.c229
-rw-r--r--usr.sbin/sysctl/sysctl.8214
-rw-r--r--usr.sbin/sysctl/sysctl.c572
-rw-r--r--usr.sbin/syslogd/Makefile9
-rw-r--r--usr.sbin/syslogd/pathnames.h40
-rw-r--r--usr.sbin/syslogd/syslog.conf.5224
-rw-r--r--usr.sbin/syslogd/syslogd.8122
-rw-r--r--usr.sbin/syslogd/syslogd.c1131
-rw-r--r--usr.sbin/tcpdump/Makefile5
-rw-r--r--usr.sbin/tcpdump/Makefile.inc3
-rw-r--r--usr.sbin/tcpdump/tcpdump/Makefile26
-rw-r--r--usr.sbin/tcpdump/tcpdump/VERSION1
-rw-r--r--usr.sbin/tcpdump/tcpdump/addrtoname.c478
-rw-r--r--usr.sbin/tcpdump/tcpdump/addrtoname.h36
-rw-r--r--usr.sbin/tcpdump/tcpdump/appletalk.h156
-rw-r--r--usr.sbin/tcpdump/tcpdump/bootp.h103
-rw-r--r--usr.sbin/tcpdump/tcpdump/bpf_dump.c61
-rw-r--r--usr.sbin/tcpdump/tcpdump/bpf_image.c282
-rw-r--r--usr.sbin/tcpdump/tcpdump/etherent.c144
-rw-r--r--usr.sbin/tcpdump/tcpdump/etherent.h34
-rw-r--r--usr.sbin/tcpdump/tcpdump/etherproto.h70
-rw-r--r--usr.sbin/tcpdump/tcpdump/extract.h49
-rw-r--r--usr.sbin/tcpdump/tcpdump/gencode.c1384
-rw-r--r--usr.sbin/tcpdump/tcpdump/gencode.h156
-rw-r--r--usr.sbin/tcpdump/tcpdump/inet.c172
-rw-r--r--usr.sbin/tcpdump/tcpdump/interface.h113
-rw-r--r--usr.sbin/tcpdump/tcpdump/md.c35
-rw-r--r--usr.sbin/tcpdump/tcpdump/md.h40
-rw-r--r--usr.sbin/tcpdump/tcpdump/mib.h1256
-rw-r--r--usr.sbin/tcpdump/tcpdump/nametoaddr.c258
-rw-r--r--usr.sbin/tcpdump/tcpdump/nametoaddr.h43
-rw-r--r--usr.sbin/tcpdump/tcpdump/ntp.h117
-rw-r--r--usr.sbin/tcpdump/tcpdump/optimize.c1871
-rw-r--r--usr.sbin/tcpdump/tcpdump/os.c26
-rw-r--r--usr.sbin/tcpdump/tcpdump/os.h85
-rw-r--r--usr.sbin/tcpdump/tcpdump/ospf.h223
-rw-r--r--usr.sbin/tcpdump/tcpdump/pcap.c209
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-arp.c100
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-atalk.c478
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-bootp.c263
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-domain.c287
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-egp.c347
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-ether.c123
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-fddi.c236
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-icmp.c207
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-ip.c393
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-nfs.c461
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-ntp.c277
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-null.c117
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-ospf.c586
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-ppp.c102
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-rip.c142
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-sl.c246
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-snmp.c1043
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-sunrpc.c130
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-tcp.c287
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-tftp.c149
-rw-r--r--usr.sbin/tcpdump/tcpdump/print-udp.c136
-rw-r--r--usr.sbin/tcpdump/tcpdump/savefile.c303
-rw-r--r--usr.sbin/tcpdump/tcpdump/savefile.h75
-rw-r--r--usr.sbin/tcpdump/tcpdump/tcpdump.11067
-rw-r--r--usr.sbin/tcpdump/tcpdump/tcpdump.c347
-rw-r--r--usr.sbin/tcpdump/tcpdump/tcpgram.y232
-rw-r--r--usr.sbin/tcpdump/tcpdump/tcplex.l144
-rw-r--r--usr.sbin/tcpdump/tcpdump/util.c278
-rw-r--r--usr.sbin/tcpdump/tcpslice/Makefile18
-rw-r--r--usr.sbin/tcpdump/tcpslice/gwtm2secs.c75
-rw-r--r--usr.sbin/tcpdump/tcpslice/search.c563
-rw-r--r--usr.sbin/tcpdump/tcpslice/tcpslice.1260
-rw-r--r--usr.sbin/tcpdump/tcpslice/tcpslice.c645
-rw-r--r--usr.sbin/timed/Makefile5
-rw-r--r--usr.sbin/timed/SMM.doc/timed/Makefile11
-rw-r--r--usr.sbin/timed/SMM.doc/timed/date53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/loop54
-rw-r--r--usr.sbin/timed/SMM.doc/timed/spell.ok34
-rw-r--r--usr.sbin/timed/SMM.doc/timed/time53
-rw-r--r--usr.sbin/timed/SMM.doc/timed/timed.ms504
-rw-r--r--usr.sbin/timed/SMM.doc/timed/unused53
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/Makefile7
-rw-r--r--usr.sbin/timed/SMM.doc/timedop/timed.ms279
-rw-r--r--usr.sbin/timed/timed/CHANGES144
-rw-r--r--usr.sbin/timed/timed/Makefile13
-rw-r--r--usr.sbin/timed/timed/acksend.c132
-rw-r--r--usr.sbin/timed/timed/byteorder.c86
-rw-r--r--usr.sbin/timed/timed/candidate.c167
-rw-r--r--usr.sbin/timed/timed/cksum.c87
-rw-r--r--usr.sbin/timed/timed/correct.c294
-rw-r--r--usr.sbin/timed/timed/extern.h89
-rw-r--r--usr.sbin/timed/timed/globals.h186
-rw-r--r--usr.sbin/timed/timed/master.c907
-rw-r--r--usr.sbin/timed/timed/measure.c353
-rw-r--r--usr.sbin/timed/timed/networkdelta.c264
-rw-r--r--usr.sbin/timed/timed/pathnames.h44
-rw-r--r--usr.sbin/timed/timed/readmsg.c488
-rw-r--r--usr.sbin/timed/timed/slave.c715
-rw-r--r--usr.sbin/timed/timed/timed.8219
-rw-r--r--usr.sbin/timed/timed/timed.c980
-rw-r--r--usr.sbin/timed/timedc/Makefile11
-rw-r--r--usr.sbin/timed/timedc/cmds.c526
-rw-r--r--usr.sbin/timed/timedc/cmdtab.c57
-rw-r--r--usr.sbin/timed/timedc/extern.h52
-rw-r--r--usr.sbin/timed/timedc/timedc.8145
-rw-r--r--usr.sbin/timed/timedc/timedc.c261
-rw-r--r--usr.sbin/timed/timedc/timedc.h66
-rw-r--r--usr.sbin/traceroute/Makefile8
-rw-r--r--usr.sbin/traceroute/README126
-rw-r--r--usr.sbin/traceroute/mean.awk50
-rw-r--r--usr.sbin/traceroute/median.awk67
-rw-r--r--usr.sbin/traceroute/traceroute.8336
-rw-r--r--usr.sbin/traceroute/traceroute.c835
-rw-r--r--usr.sbin/trpt/Makefile8
-rw-r--r--usr.sbin/trpt/trpt.8151
-rw-r--r--usr.sbin/trpt/trpt.c414
-rw-r--r--usr.sbin/trsp/Makefile9
-rw-r--r--usr.sbin/trsp/trsp.8141
-rw-r--r--usr.sbin/trsp/trsp.c433
-rw-r--r--usr.sbin/tzsetup/Makefile12
-rw-r--r--usr.sbin/tzsetup/tzsetup.sh181
-rw-r--r--usr.sbin/update/Makefile6
-rw-r--r--usr.sbin/update/update.874
-rw-r--r--usr.sbin/update/update.c75
-rw-r--r--usr.sbin/vidcontrol/Makefile4
-rw-r--r--usr.sbin/vidcontrol/decode.c74
-rw-r--r--usr.sbin/vidcontrol/path.h4
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.1118
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.c481
-rw-r--r--usr.sbin/vipw/Makefile7
-rw-r--r--usr.sbin/vipw/pw_util.c204
-rw-r--r--usr.sbin/vipw/pw_util.h42
-rw-r--r--usr.sbin/vipw/vipw.893
-rw-r--r--usr.sbin/vipw/vipw.c127
-rw-r--r--usr.sbin/xntpd/Config200
-rw-r--r--usr.sbin/xntpd/Config.sed14
-rw-r--r--usr.sbin/xntpd/Makefile344
-rw-r--r--usr.sbin/xntpd/Makefile.inc7
-rw-r--r--usr.sbin/xntpd/README.FreeBSD84
-rw-r--r--usr.sbin/xntpd/authstuff/Makefile27
-rw-r--r--usr.sbin/xntpd/authstuff/md5driver.c12
-rw-r--r--usr.sbin/xntpd/clockstuff/Makefile16
-rw-r--r--usr.sbin/xntpd/compilers/hpux10+.cc1
-rw-r--r--usr.sbin/xntpd/doc/ntpq.8321
-rw-r--r--usr.sbin/xntpd/include/ntp_machine.h58
-rw-r--r--usr.sbin/xntpd/lib/Makefile30
-rw-r--r--usr.sbin/xntpd/lib/authdes.c.export2
-rw-r--r--usr.sbin/xntpd/lib/msyslog.c8
-rw-r--r--usr.sbin/xntpd/machines/hpux10+8
-rw-r--r--usr.sbin/xntpd/ntpdate/Makefile28
-rw-r--r--usr.sbin/xntpd/ntpq/Makefile29
-rw-r--r--usr.sbin/xntpd/ntpq/ntpq.c154
-rw-r--r--usr.sbin/xntpd/ntptrace/Makefile28
-rw-r--r--usr.sbin/xntpd/parse/Makefile19
-rw-r--r--usr.sbin/xntpd/parse/util/Makefile49
-rw-r--r--usr.sbin/xntpd/util/Makefile28
-rw-r--r--usr.sbin/xntpd/util/tickadj.c18
-rw-r--r--usr.sbin/xntpd/xntpd/Makefile45
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_control.c317
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_loopfilter.c1184
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_request.c404
-rw-r--r--usr.sbin/xntpd/xntpd/ntp_unixclock.c94
-rw-r--r--usr.sbin/xntpd/xntpd/refclock_trak.c1083
-rw-r--r--usr.sbin/xntpd/xntpdc/Makefile28
-rw-r--r--usr.sbin/xntpd/xntpdc/ntpdc.c98
-rw-r--r--usr.sbin/xntpd/xntpres/Makefile28
-rw-r--r--usr.sbin/ypbind/Makefile8
-rw-r--r--usr.sbin/ypbind/ypbind.c672
-rw-r--r--usr.sbin/yppoll/Makefile7
-rw-r--r--usr.sbin/yppoll/yppoll.c101
-rw-r--r--usr.sbin/ypset/Makefile7
-rw-r--r--usr.sbin/ypset/ypset.c154
-rw-r--r--usr.sbin/zic/Makefile5
-rw-r--r--usr.sbin/zic/Makefile.inc3
-rw-r--r--usr.sbin/zic/README72
-rw-r--r--usr.sbin/zic/Theory120
-rw-r--r--usr.sbin/zic/ialloc.c103
-rw-r--r--usr.sbin/zic/scheck.c62
-rw-r--r--usr.sbin/zic/zdump.840
-rw-r--r--usr.sbin/zic/zdump.c307
-rw-r--r--usr.sbin/zic/zdump/Makefile13
-rw-r--r--usr.sbin/zic/zic.8412
-rw-r--r--usr.sbin/zic/zic.c1939
-rw-r--r--usr.sbin/zic/zic/Makefile13
1162 files changed, 300143 insertions, 1777 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
new file mode 100644
index 0000000..25ade54
--- /dev/null
+++ b/usr.sbin/Makefile
@@ -0,0 +1,40 @@
+# @(#)Makefile 5.20 (Berkeley) 6/12/93
+
+# XXX MISSING: mkproto
+# XXX MISSING SOURCES: quot
+# XXX TEMP. BROKEN: iostat
+SUBDIR= ac accton amd arp bootpd bootpef bootpgw bootptest chown chroot \
+ cron crunch dbsym dev_mkdb diskpart edquota fdformat fdwrite \
+ inetd kbdcontrol kgmon kvm_mkdb lpr lptcontrol \
+ manctl mtree mrouted named nslookup pkg_install portmap pstat \
+ pwd_mkdb quotaon repquota routed rmt rtprio rwhod sa sendmail \
+ sliplogin sysctl syslogd tcpdump traceroute trpt tzsetup vidcontrol \
+ vipw xntpd ypbind yppoll ypset zic
+
+#
+# XNSrouted and trsp are of very marginal utility to anyone at this
+# point. Users who actually have a use for these programs (unlikely)
+# are free to add them back in.
+#
+# SUBDIR+=XNSrouted trsp
+
+.if make(clean) || make(cleandir)
+SUBDIR+=bad144 config config.new eeprom iostat swapinfo timed
+.elif ${MACHINE} == "hp300"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "i386"
+SUBDIR+=bad144 config swapinfo timed
+# iostat
+.elif ${MACHINE} == "luna68k"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "mips"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "sparc"
+SUBDIR+=config.new eeprom timed
+.elif ${MACHINE} == "tahoe"
+SUBDIR+=config iostat timed
+.elif ${MACHINE} == "vax"
+SUBDIR+=bad144 config iostat timed
+.endif
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/Makefile.inc b/usr.sbin/Makefile.inc
new file mode 100644
index 0000000..fd92864
--- /dev/null
+++ b/usr.sbin/Makefile.inc
@@ -0,0 +1,3 @@
+# @(#)Makefile.inc 8.1 (Berkeley) 6/6/93
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/XNSrouted/Makefile b/usr.sbin/XNSrouted/Makefile
new file mode 100644
index 0000000..0c9d6e3
--- /dev/null
+++ b/usr.sbin/XNSrouted/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= XNSrouted
+MAN8= XNSrouted.8
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c trace.c
+DPADD= ${LIBCOMPAT}
+LDADD= -lcompat
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/XNSrouted/XNSrouted.8 b/usr.sbin/XNSrouted/XNSrouted.8
new file mode 100644
index 0000000..7b278bd
--- /dev/null
+++ b/usr.sbin/XNSrouted/XNSrouted.8
@@ -0,0 +1,186 @@
+.\" 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.
+.\"
+.\" @(#)XNSrouted.8 8.1 (Berkeley) 6/5/93
+.\"
+.Dd June 5, 1993
+.Dt XNSROUTED 8
+.Os BSD 4.3
+.Sh NAME
+.Nm XNSrouted
+.Nd NS Routing Information Protocol daemon
+.Sh SYNOPSIS
+.Nm XNSrouted
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm XNSrouted
+is invoked at boot time to manage the Xerox NS routing tables.
+The NS routing daemon uses the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+.Pp
+Available options:
+.Bl -tag -width logfile
+.It Fl q
+Do not supply routing information (opposite of
+.Fl s
+option below).
+.It Fl s
+Forces
+.Nm XNSrouted
+to supply routing information whether it is acting as an internetwork
+router or not.
+.It Fl t
+All packets sent or received are
+printed on the standard output. In addition,
+.Nm XNSrouted
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.It Ar logfile
+Name of file in which
+.Nm XNSrouted Ns 's
+actions should be logged. This log contains information
+about any changes to the routing tables and a history of
+recent messages sent and received which are related to
+the changed route.
+.El
+.Pp
+In normal operation
+.Nm XNSrouted
+listens
+for routing information packets. If the host is connected to
+multiple NS networks, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm XNSrouted
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked
+.Dq up
+(the software loopback interface
+is ignored). If multiple interfaces
+are present, it is assumed the host will forward packets
+between networks.
+.Nm XNSrouted
+then transmits a
+.Em request
+packet on each interface (using a broadcast packet if
+the interface supports it) and enters a loop, listening
+for
+.Em request
+and
+.Em response
+packets from other hosts.
+.Pp
+When a
+.Em request
+packet is received,
+.Nm XNSrouted
+formulates a reply based on the information maintained in its
+internal tables. The
+.Em response
+packet generated contains a list of known routes, each marked
+with a
+.Dq hop count
+metric (a count of 16, or greater, is
+considered
+.Dq infinite ) .
+The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm XNSrouted
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -bullet
+.It
+No routing table entry exists for the destination network
+or host, and the metric indicates the destination is ``reachable''
+(i.e. the hop count is not infinite).
+.It
+The source host of the packet is the same as the router in the
+existing routing table entry. That is, updated information is
+being received from the very internetwork router through which
+packets for the destination are being routed.
+.It
+The existing entry in the routing table has not been updated for
+some time (defined to be 90 seconds) and the route is at least
+as cost effective as the current route.
+.It
+The new route describes a shorter route to the destination than
+the one currently stored in the routing tables; the metric of
+the new route is compared against the one stored in the table
+to decide this.
+.El
+.Pp
+When an update is applied,
+.Nm XNSrouted
+records the change in its internal tables and generates a
+.Em response
+packet to all directly connected hosts and networks.
+.Xr Routed 8
+waits a short period
+of time (no more than 30 seconds) before modifying the kernel's
+routing tables to allow possible unstable situations to settle.
+.Pp
+In addition to processing incoming packets,
+.Nm XNSrouted
+also periodically checks the routing table entries.
+If an entry has not been updated for 3 minutes, the entry's metric
+is set to infinity and marked for deletion. Deletions are delayed
+an additional 60 seconds to insure the invalidation is propagated
+to other routers.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+.Sh SEE ALSO
+.Xr idp 4
+.Rs
+.%T "Internet Transport Protocols"
+.%R "XSIS 028112"
+.%Q "Xerox System Integration Standard"
+.Re
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.sbin/XNSrouted/af.c b/usr.sbin/XNSrouted/af.c
new file mode 100644
index 0000000..6c81b47
--- /dev/null
+++ b/usr.sbin/XNSrouted/af.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)af.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+int null_hash(), null_netmatch(), null_output(),
+ null_portmatch(), null_portcheck(),
+ null_checkhost(), null_ishost(), null_canon();
+int xnnet_hash(), xnnet_netmatch(), xnnet_output(),
+ xnnet_portmatch(),
+ xnnet_checkhost(), xnnet_ishost(), xnnet_canon();
+#define NIL \
+ { null_hash, null_netmatch, null_output, \
+ null_portmatch, null_portcheck, null_checkhost, \
+ null_ishost, null_canon }
+#define XNSNET \
+ { xnnet_hash, xnnet_netmatch, xnnet_output, \
+ xnnet_portmatch, xnnet_portmatch, xnnet_checkhost, \
+ xnnet_ishost, xnnet_canon }
+
+struct afswitch afswitch[AF_MAX] =
+ { NIL, NIL, NIL, NIL, NIL, NIL, XNSNET, NIL, NIL, NIL, NIL };
+
+struct sockaddr_ns xnnet_default = { sizeof(struct sockaddr_ns), AF_NS };
+
+union ns_net ns_anynet;
+union ns_net ns_zeronet;
+
+xnnet_hash(sns, hp)
+ register struct sockaddr_ns *sns;
+ struct afhash *hp;
+{
+ register long hash = 0;
+ register u_short *s = sns->sns_addr.x_host.s_host;
+ union ns_net_u net;
+
+ net.net_e = sns->sns_addr.x_net;
+ hp->afh_nethash = net.long_e;
+ hash = *s++; hash <<= 8; hash += *s++; hash <<= 8; hash += *s;
+ hp->afh_hosthash = hash;
+}
+
+xnnet_netmatch(sxn1, sxn2)
+ struct sockaddr_ns *sxn1, *sxn2;
+{
+ return (ns_neteq(sxn1->sns_addr, sxn2->sns_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+xnnet_portmatch(sns)
+ register struct sockaddr_ns *sns;
+{
+
+ return (ntohs(sns->sns_addr.x_port) == IDPPORT_RIF );
+}
+
+
+/*
+ * xns output routine.
+ */
+#ifdef DEBUG
+int do_output = 0;
+#endif
+xnnet_output(flags, sns, size)
+ int flags;
+ struct sockaddr_ns *sns;
+ int size;
+{
+ struct sockaddr_ns dst;
+
+ dst = *sns;
+ sns = &dst;
+ if (sns->sns_addr.x_port == 0)
+ sns->sns_addr.x_port = htons(IDPPORT_RIF);
+#ifdef DEBUG
+ if(do_output || ntohs(msg->rip_cmd) == RIPCMD_REQUEST)
+#endif
+ /*
+ * Kludge to allow us to get routes out to machines that
+ * don't know their addresses yet; send to that address on
+ * ALL connected nets
+ */
+ if (ns_neteqnn(sns->sns_addr.x_net, ns_zeronet)) {
+ extern struct interface *ifnet;
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ sns->sns_addr.x_net =
+ satons_addr(ifp->int_addr).x_net;
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sns, sizeof (*sns));
+ }
+ return;
+ }
+
+ (void) sendto(s, msg, size, flags,
+ (struct sockaddr *)sns, sizeof (*sns));
+}
+
+/*
+ * Return 1 if we want this route.
+ * We use this to disallow route net G entries for one for multiple
+ * point to point links.
+ */
+xnnet_checkhost(sns)
+ struct sockaddr_ns *sns;
+{
+ register struct interface *ifp = if_ifwithnet(sns);
+ /*
+ * We want this route if there is no more than one
+ * point to point interface with this network.
+ */
+ if (ifp == 0 || (ifp->int_flags & IFF_POINTOPOINT)==0) return (1);
+ return (ifp->int_sq.n == ifp->int_sq.p);
+}
+
+/*
+ * Return 1 if the address is
+ * for a host, 0 for a network.
+ */
+xnnet_ishost(sns)
+struct sockaddr_ns *sns;
+{
+ register u_short *s = sns->sns_addr.x_host.s_host;
+
+ if ((s[0]==0xffff) && (s[1]==0xffff) && (s[2]==0xffff))
+ return (0);
+ else
+ return (1);
+}
+
+xnnet_canon(sns)
+ struct sockaddr_ns *sns;
+{
+
+ sns->sns_addr.x_port = 0;
+}
+
+/*ARGSUSED*/
+null_hash(addr, hp)
+ struct sockaddr *addr;
+ struct afhash *hp;
+{
+
+ hp->afh_nethash = hp->afh_hosthash = 0;
+}
+
+/*ARGSUSED*/
+null_netmatch(a1, a2)
+ struct sockaddr *a1, *a2;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_output(s, f, a1, n)
+ int s, f;
+ struct sockaddr *a1;
+ int n;
+{
+
+ ;
+}
+
+/*ARGSUSED*/
+null_portmatch(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_portcheck(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_ishost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_checkhost(a1)
+ struct sockaddr *a1;
+{
+
+ return (0);
+}
+
+/*ARGSUSED*/
+null_canon(a1)
+ struct sockaddr *a1;
+{
+
+ ;
+}
diff --git a/usr.sbin/XNSrouted/af.h b/usr.sbin/XNSrouted/af.h
new file mode 100644
index 0000000..9b74463
--- /dev/null
+++ b/usr.sbin/XNSrouted/af.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ *
+ * @(#)af.h 5.1 (Berkeley) 6/4/85 (routed/af.h)
+ *
+ * @(#)af.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Per address family routines.
+ */
+struct afswitch {
+ int (*af_hash)(); /* returns keys based on address */
+ int (*af_netmatch)(); /* verifies net # matching */
+ int (*af_output)(); /* interprets address for sending */
+ int (*af_portmatch)(); /* packet from some other router? */
+ int (*af_portcheck)(); /* packet from privileged peer? */
+ int (*af_checkhost)(); /* tells if address for host or net */
+ int (*af_ishost)(); /* tells if address is valid */
+ int (*af_canon)(); /* canonicalize address for compares */
+};
+
+/*
+ * Structure returned by af_hash routines.
+ */
+struct afhash {
+ u_int afh_hosthash; /* host based hash */
+ u_int afh_nethash; /* network based hash */
+};
+
+struct afswitch afswitch[AF_MAX]; /* table proper */
diff --git a/usr.sbin/XNSrouted/defs.h b/usr.sbin/XNSrouted/defs.h
new file mode 100644
index 0000000..c6f8b5f
--- /dev/null
+++ b/usr.sbin/XNSrouted/defs.h
@@ -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.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/route.h>
+#include <netns/ns.h>
+#include <netns/idp.h>
+#if defined(vax) || defined(pdp11)
+#define xnnet(x) ((u_long) (x)->rip_dst[1] << 16 | (u_long) (x)->rip_dst[0] )
+#else
+#define xnnet(x) ((u_long) (x)->rip_dst[0] << 16 | (u_long) (x)->rip_dst[1] )
+#endif
+#define IDPPORT_RIF 1
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include "protocol.h"
+#include "trace.h"
+#include "interface.h"
+#include "table.h"
+#include "af.h"
+
+
+/*
+ * When we find any interfaces marked down we rescan the
+ * kernel every CHECK_INTERVAL seconds to see if they've
+ * come up.
+ */
+#define CHECK_INTERVAL (5*60)
+
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+#define min(a,b) ((a)>(b)?(b):(a))
+
+struct sockaddr_ns addr; /* Daemon's Address */
+int s; /* Socket to listen on */
+int kmem;
+int supplier; /* process should supply updates */
+int install; /* if 1 call kernel */
+int lookforinterfaces; /* if 1 probe kernel for new up interfaces */
+int performnlist; /* if 1 check if /kernel has changed */
+int externalinterfaces; /* # of remote and local interfaces */
+int timeval; /* local idea of time */
+int noteremoterequests; /* squawk on requests from non-local nets */
+int r; /* Routing socket to install updates with */
+struct sockaddr_ns ns_netmask; /* Used in installing routes */
+
+char packet[MAXPACKETSIZE+sizeof(struct idp)+1];
+struct rip *msg;
+
+char **argv0;
+
+int sndmsg();
+int supply();
+int cleanup();
+int rtioctl();
+#define ADD 1
+#define DELETE 2
+#define CHANGE 3
diff --git a/usr.sbin/XNSrouted/if.c b/usr.sbin/XNSrouted/if.c
new file mode 100644
index 0000000..422f757
--- /dev/null
+++ b/usr.sbin/XNSrouted/if.c
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * static char sccsid[] = "@(#)if.c 5.1 (Berkeley) 6/4/85"; (routed/if.c)
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Find the interface with address addr.
+ */
+struct interface *
+if_ifwithaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+#define same(a1, a2) \
+ (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (ifp->int_addr.sa_family != addr->sa_family)
+ continue;
+ if (same(&ifp->int_addr, addr))
+ break;
+ if ((ifp->int_flags & IFF_BROADCAST) &&
+ same(&ifp->int_broadaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the point-to-point interface with destination address addr.
+ */
+struct interface *
+if_ifwithdstaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
+ continue;
+ if (same(&ifp->int_dstaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the interface on the network
+ * of the specified address.
+ */
+struct interface *
+if_ifwithnet(addr)
+ register struct sockaddr *addr;
+{
+ register struct interface *ifp;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= AF_MAX)
+ return (0);
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (af != ifp->int_addr.sa_family)
+ continue;
+ if ((*netmatch)(addr, &ifp->int_addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find an interface from which the specified address
+ * should have come from. Used for figuring out which
+ * interface a packet came in on -- for tracing.
+ */
+struct interface *
+if_iflookup(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp, *maybe;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= AF_MAX)
+ return (0);
+ maybe = 0;
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_addr.sa_family != af)
+ continue;
+ if (same(&ifp->int_addr, addr))
+ break;
+ if ((ifp->int_flags & IFF_BROADCAST) &&
+ same(&ifp->int_broadaddr, addr))
+ break;
+ if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
+ maybe = ifp;
+ }
+ if (ifp == 0)
+ ifp = maybe;
+ return (ifp);
+}
diff --git a/usr.sbin/XNSrouted/input.c b/usr.sbin/XNSrouted/input.c
new file mode 100644
index 0000000..b64fca2
--- /dev/null
+++ b/usr.sbin/XNSrouted/input.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * XNS Routing Table Management Daemon
+ */
+#include "defs.h"
+
+struct sockaddr *
+xns_nettosa(net)
+union ns_net net;
+{
+ static struct sockaddr_ns sxn;
+ extern char ether_broadcast_addr[6];
+
+ bzero(&sxn, sizeof (struct sockaddr_ns));
+ sxn.sns_family = AF_NS;
+ sxn.sns_len = sizeof (sxn);
+ sxn.sns_addr.x_net = net;
+ sxn.sns_addr.x_host = *(union ns_host *)ether_broadcast_addr;
+ return( (struct sockaddr *)&sxn);
+
+}
+
+/*
+ * Process a newly received packet.
+ */
+rip_input(from, size)
+ struct sockaddr *from;
+ int size;
+{
+ struct rt_entry *rt;
+ struct netinfo *n;
+ struct interface *ifp;
+ int newsize;
+ struct afswitch *afp;
+
+
+ ifp = 0;
+ TRACE_INPUT(ifp, from, size);
+ if (from->sa_family >= AF_MAX)
+ return;
+ afp = &afswitch[from->sa_family];
+
+ size -= sizeof (u_short) /* command */;
+ n = msg->rip_nets;
+
+ switch (ntohs(msg->rip_cmd)) {
+
+ case RIPCMD_REQUEST:
+ newsize = 0;
+ while (size > 0) {
+ if (size < sizeof (struct netinfo))
+ break;
+ size -= sizeof (struct netinfo);
+
+ /*
+ * A single entry with rip_dst == DSTNETS_ALL and
+ * metric ``infinity'' means ``all routes''.
+ */
+ if (ns_neteqnn(n->rip_dst, ns_anynet) &&
+ ntohs(n->rip_metric) == HOPCNT_INFINITY &&
+ size == 0) {
+ ifp = if_ifwithnet(from);
+ supply(from, 0, ifp);
+ return;
+ }
+ /*
+ * request for specific nets
+ */
+ rt = rtlookup(xns_nettosa(n->rip_dst));
+ if (ftrace) {
+ fprintf(ftrace,
+ "specific request for %s",
+ xns_nettoa(n->rip_dst));
+ fprintf(ftrace,
+ " yields route %x\n",
+ rt);
+ }
+ n->rip_metric = htons( rt == 0 ? HOPCNT_INFINITY :
+ min(rt->rt_metric+1, HOPCNT_INFINITY));
+ n++;
+ newsize += sizeof (struct netinfo);
+ }
+ if (newsize > 0) {
+ msg->rip_cmd = htons(RIPCMD_RESPONSE);
+ newsize += sizeof (u_short);
+ /* should check for if with dstaddr(from) first */
+ (*afp->af_output)(0, from, newsize);
+ ifp = if_ifwithnet(from);
+ TRACE_OUTPUT(ifp, from, newsize);
+ if (ftrace) {
+ fprintf(ftrace,
+ "request arrived on interface %s\n",
+ ifp->int_name);
+ }
+ }
+ return;
+
+ case RIPCMD_RESPONSE:
+ /* verify message came from a router */
+ if ((*afp->af_portmatch)(from) == 0)
+ return;
+ (*afp->af_canon)(from);
+ /* are we talking to ourselves? */
+ if (ifp = if_ifwithaddr(from)) {
+ rt = rtfind(from);
+ if (rt == 0 || (rt->rt_state & RTS_INTERFACE) == 0)
+ addrouteforif(ifp);
+ else
+ rt->rt_timer = 0;
+ return;
+ }
+ /* Update timer for interface on which the packet arrived.
+ * If from other end of a point-to-point link that isn't
+ * in the routing tables, (re-)add the route.
+ */
+ if ((rt = rtfind(from)) && (rt->rt_state & RTS_INTERFACE)) {
+ if(ftrace) fprintf(ftrace, "Got route\n");
+ rt->rt_timer = 0;
+ } else if (ifp = if_ifwithdstaddr(from)) {
+ if(ftrace) fprintf(ftrace, "Got partner\n");
+ addrouteforif(ifp);
+ }
+ for (; size > 0; size -= sizeof (struct netinfo), n++) {
+ struct sockaddr *sa;
+ if (size < sizeof (struct netinfo))
+ break;
+ if ((unsigned) ntohs(n->rip_metric) >= HOPCNT_INFINITY)
+ continue;
+ rt = rtfind(sa = xns_nettosa(n->rip_dst));
+ if (rt == 0) {
+ rtadd(sa, from, ntohs(n->rip_metric), 0);
+ continue;
+ }
+
+ /*
+ * Update if from gateway and different,
+ * from anywhere and shorter, or getting stale and equivalent.
+ */
+ if ((equal(from, &rt->rt_router) &&
+ ntohs(n->rip_metric) != rt->rt_metric ) ||
+ (unsigned) ntohs(n->rip_metric) < rt->rt_metric ||
+ (rt->rt_timer > (EXPIRE_TIME/2) &&
+ rt->rt_metric == ntohs(n->rip_metric))) {
+ rtchange(rt, from, ntohs(n->rip_metric));
+ rt->rt_timer = 0;
+ }
+ }
+ return;
+ }
+}
diff --git a/usr.sbin/XNSrouted/interface.h b/usr.sbin/XNSrouted/interface.h
new file mode 100644
index 0000000..64e1580
--- /dev/null
+++ b/usr.sbin/XNSrouted/interface.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ * @(#)interface.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ * We list only one address for each interface, the AF_XNS one.
+ */
+#define NIFADDR 3
+struct interface {
+ struct interface *int_next;
+ struct sockaddr int_addr; /* address on this host */
+ union {
+ struct sockaddr intu_broadaddr;
+ struct sockaddr intu_dstaddr;
+ } int_intu;
+#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
+#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
+ int int_metric; /* init's routing entry */
+ int int_flags; /* see below */
+ struct ifdebug int_input, int_output; /* packet tracing stuff */
+ int int_ipackets; /* input packets received */
+ int int_opackets; /* output packets sent */
+ char *int_name; /* from kernel if structure */
+ u_short int_transitions; /* times gone up-down */
+/*XNS Specific entry */
+ struct sameq {
+ struct sameq *n; /* q of other pt-to-pt links */
+ struct sameq *p; /* with same net # */
+ } int_sq;
+};
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_ROUTE 0x8 /* routing entry installed */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+
+#define IFF_PASSIVE 0x2000 /* can't tell if up/down */
+#define IFF_INTERFACE 0x4000 /* hardware interface */
+#define IFF_REMOTE 0x8000 /* interface isn't on this machine */
+
+struct interface *if_ifwithaddr();
+struct interface *if_ifwithdstaddr();
+struct interface *if_ifwithnet();
+struct interface *if_iflookup();
diff --git a/usr.sbin/XNSrouted/main.c b/usr.sbin/XNSrouted/main.c
new file mode 100644
index 0000000..601a005
--- /dev/null
+++ b/usr.sbin/XNSrouted/main.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * XNS Routing Information Protocol Daemon
+ */
+#include "defs.h"
+#include <sys/time.h>
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <nlist.h>
+#include <signal.h>
+#include <paths.h>
+
+int supplier = -1; /* process should supply updates */
+extern int gateway;
+
+struct rip *msg = (struct rip *) &packet[sizeof (struct idp)];
+void hup(), fkexit(), timer();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int cc;
+ struct sockaddr from;
+ u_char retry;
+
+ argv0 = argv;
+ argv++, argc--;
+ while (argc > 0 && **argv == '-') {
+ if (strcmp(*argv, "-s") == 0) {
+ supplier = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-q") == 0) {
+ supplier = 0;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-R") == 0) {
+ noteremoterequests++;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-t") == 0) {
+ tracepackets++;
+ argv++, argc--;
+ ftrace = stderr;
+ tracing = 1;
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ gateway = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-l") == 0) {
+ gateway = -1;
+ argv++, argc--;
+ continue;
+ }
+ fprintf(stderr,
+ "usage: xnsrouted [ -s ] [ -q ] [ -t ] [ -g ] [ -l ]\n");
+ exit(1);
+ }
+
+
+#ifndef DEBUG
+ if (!tracepackets)
+ daemon(0, 0);
+#endif
+ openlog("XNSrouted", LOG_PID, LOG_DAEMON);
+
+ addr.sns_family = AF_NS;
+ addr.sns_len = sizeof(addr);
+ addr.sns_port = htons(IDPPORT_RIF);
+ ns_anynet.s_net[0] = ns_anynet.s_net[1] = -1;
+ ns_netmask.sns_addr.x_net = ns_anynet;
+ ns_netmask.sns_len = 6;
+ r = socket(AF_ROUTE, SOCK_RAW, 0);
+ /* later, get smart about lookingforinterfaces */
+ if (r)
+ shutdown(r, 0); /* for now, don't want reponses */
+ else {
+ fprintf(stderr, "routed: no routing socket\n");
+ exit(1);
+ }
+ s = getsocket(SOCK_DGRAM, 0, &addr);
+ if (s < 0)
+ exit(1);
+ /*
+ * Any extra argument is considered
+ * a tracing log file.
+ */
+ if (argc > 0)
+ traceon(*argv);
+ /*
+ * Collect an initial view of the world by
+ * snooping in the kernel. Then, send a request packet on all
+ * directly connected networks to find out what
+ * everyone else thinks.
+ */
+ rtinit();
+ ifinit();
+ if (supplier < 0)
+ supplier = 0;
+ /* request the state of the world */
+ msg->rip_cmd = htons(RIPCMD_REQUEST);
+ msg->rip_nets[0].rip_dst = ns_anynet;
+ msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY);
+ toall(sndmsg);
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGINT, hup);
+ signal(SIGEMT, fkexit);
+ timer();
+
+
+ for (;;)
+ process(s);
+
+}
+
+process(fd)
+ int fd;
+{
+ struct sockaddr from;
+ int fromlen = sizeof (from), cc, omask;
+ struct idp *idp = (struct idp *)packet;
+
+ cc = recvfrom(fd, packet, sizeof (packet), 0, &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EINTR)
+ syslog(LOG_ERR, "recvfrom: %m");
+ return;
+ }
+ if (tracepackets > 1 && ftrace) {
+ fprintf(ftrace,"rcv %d bytes on %s ", cc, xns_ntoa(&idp->idp_dna));
+ fprintf(ftrace," from %s\n", xns_ntoa(&idp->idp_sna));
+ }
+
+ if (noteremoterequests && !ns_neteqnn(idp->idp_sna.x_net, ns_zeronet)
+ && !ns_neteq(idp->idp_sna, idp->idp_dna))
+ {
+ syslog(LOG_ERR,
+ "net of interface (%s) != net on ether (%s)!\n",
+ xns_nettoa(idp->idp_dna.x_net),
+ xns_nettoa(idp->idp_sna.x_net));
+ }
+
+ /* We get the IDP header in front of the RIF packet*/
+ cc -= sizeof (struct idp);
+#define mask(s) (1<<((s)-1))
+ omask = sigblock(mask(SIGALRM));
+ rip_input(&from, cc);
+ sigsetmask(omask);
+}
+
+getsocket(type, proto, sns)
+ int type, proto;
+ struct sockaddr_ns *sns;
+{
+ int domain = sns->sns_family;
+ int retry, s, on = 1;
+
+ retry = 1;
+ while ((s = socket(domain, type, proto)) < 0 && retry) {
+ syslog(LOG_ERR, "socket: %m");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ while (bind(s, (struct sockaddr *)sns, sizeof (*sns)) < 0 && retry) {
+ syslog(LOG_ERR, "bind: %m");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ if (domain==AF_NS) {
+ struct idp idp;
+ if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
+ syslog(LOG_ERR, "setsockopt SEE HEADERS: %m");
+ exit(1);
+ }
+ idp.idp_pt = NSPROTO_RI;
+ if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) {
+ syslog(LOG_ERR, "setsockopt SET HEADER: %m");
+ exit(1);
+ }
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ exit(1);
+ }
+ return (s);
+}
+
+/*
+ * Fork and exit on EMT-- for profiling.
+ */
+void
+fkexit()
+{
+ if (fork() == 0)
+ exit(0);
+}
diff --git a/usr.sbin/XNSrouted/output.c b/usr.sbin/XNSrouted/output.c
new file mode 100644
index 0000000..fae1c39
--- /dev/null
+++ b/usr.sbin/XNSrouted/output.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+/*
+ * Apply the function "f" to all non-passive
+ * interfaces. If the interface supports the
+ * use of broadcasting use it, otherwise address
+ * the output to the known router.
+ */
+toall(f)
+ int (*f)();
+{
+ register struct interface *ifp;
+ register struct sockaddr *dst;
+ register int flags;
+ extern struct interface *ifnet;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_PASSIVE)
+ continue;
+ dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
+ ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
+ &ifp->int_addr;
+ flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
+ (*f)(dst, flags, ifp);
+ }
+}
+
+/*
+ * Output a preformed packet.
+ */
+/*ARGSUSED*/
+sndmsg(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+
+ (*afswitch[dst->sa_family].af_output)
+ (flags, dst, sizeof (struct rip));
+ TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
+}
+
+/*
+ * Supply dst with the contents of the routing tables.
+ * If this won't fit in one packet, chop it up into several.
+ */
+supply(dst, flags, ifp)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register struct netinfo *nn;
+ register struct netinfo *n = msg->rip_nets;
+ struct rthash *base = hosthash;
+ struct sockaddr_ns *sns = (struct sockaddr_ns *) dst;
+ int (*output)() = afswitch[dst->sa_family].af_output;
+ int doinghost = 1, size, metric;
+ union ns_net net;
+
+ msg->rip_cmd = ntohs(RIPCMD_RESPONSE);
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ size = (char *)n - (char *)msg;
+ if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+ (*output)(flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ n = msg->rip_nets;
+ }
+ sns = (struct sockaddr_ns *)&rt->rt_dst;
+ if ((rt->rt_flags & (RTF_HOST|RTF_GATEWAY)) == RTF_HOST)
+ sns = (struct sockaddr_ns *)&rt->rt_router;
+ metric = min(rt->rt_metric + 1, HOPCNT_INFINITY);
+ net = sns->sns_addr.x_net;
+ /*
+ * Make sure that we don't put out a two net entries
+ * for a pt to pt link (one for the G route, one for the if)
+ * This is a kludge, and won't work if there are lots of nets.
+ */
+ for (nn = msg->rip_nets; nn < n; nn++) {
+ if (ns_neteqnn(net, nn->rip_dst)) {
+ if (metric < ntohs(nn->rip_metric))
+ nn->rip_metric = htons(metric);
+ goto next;
+ }
+ }
+ n->rip_dst = net;
+ n->rip_metric = htons(metric);
+ n++;
+ next:;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (n != msg->rip_nets) {
+ size = (char *)n - (char *)msg;
+ (*output)(flags, dst, size);
+ TRACE_OUTPUT(ifp, dst, size);
+ }
+}
diff --git a/usr.sbin/XNSrouted/protocol.h b/usr.sbin/XNSrouted/protocol.h
new file mode 100644
index 0000000..72b0ddb
--- /dev/null
+++ b/usr.sbin/XNSrouted/protocol.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)protocol.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Xerox Routing Information Protocol
+ *
+ */
+
+struct netinfo {
+ union ns_net rip_dst; /* destination net */
+ u_short rip_metric; /* cost of route */
+};
+
+struct rip {
+ u_short rip_cmd; /* request/response */
+ struct netinfo rip_nets[1]; /* variable length */
+};
+
+/*
+ * Packet types.
+ */
+#define RIPCMD_REQUEST 1 /* want info */
+#define RIPCMD_RESPONSE 2 /* responding to request */
+
+#define RIPCMD_MAX 3
+#ifdef RIPCMDS
+char *ripcmds[RIPCMD_MAX] =
+ { "#0", "REQUEST", "RESPONSE" };
+#endif
+
+#define HOPCNT_INFINITY 16 /* per Xerox NS */
+#define DSTNETS_ALL 0xffffffff /* per Xerox NS */
+#define MAXPACKETSIZE 512 /* max broadcast size */
+
+extern union ns_net ns_anynet;
+extern union ns_net ns_zeronet;
+
+/*
+ * Timer values used in managing the routing table.
+ * Every update forces an entry's timer to be reset. After
+ * EXPIRE_TIME without updates, the entry is marked invalid,
+ * but held onto until GARBAGE_TIME so that others may
+ * see it "be deleted".
+ */
+#define TIMER_RATE 30 /* alarm clocks every 30 seconds */
+
+#define SUPPLY_INTERVAL 30 /* time to supply tables */
+
+#define EXPIRE_TIME 180 /* time to mark entry invalid */
+#define GARBAGE_TIME 240 /* time to garbage collect */
diff --git a/usr.sbin/XNSrouted/startup.c b/usr.sbin/XNSrouted/startup.c
new file mode 100644
index 0000000..bcb5615
--- /dev/null
+++ b/usr.sbin/XNSrouted/startup.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)startup.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+
+#include <nlist.h>
+#include <stdlib.h>
+
+struct interface *ifnet;
+int lookforinterfaces = 1;
+int performnlist = 1;
+int gateway = 0;
+int externalinterfaces = 0; /* # of remote and local interfaces */
+char ether_broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+
+void
+quit(s)
+ char *s;
+{
+ extern int errno;
+ int sverrno = errno;
+
+ (void) fprintf(stderr, "route: ");
+ if (s)
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(1);
+ /* NOTREACHED */
+}
+
+struct rt_addrinfo info;
+/* Sleazy use of local variables throughout file, warning!!!! */
+#define netmask info.rti_info[RTAX_NETMASK]
+#define ifaaddr info.rti_info[RTAX_IFA]
+#define brdaddr info.rti_info[RTAX_BRD]
+
+#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;
+
+ bzero(rtinfo->rti_info, 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);
+ }
+}
+
+/*
+ * Find the network interfaces which have configured themselves.
+ * If the interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
+ */
+ifinit()
+{
+ struct interface ifs, *ifp;
+ size_t needed;
+ int mib[6], no_nsaddr = 0, flags = 0;
+ char *buf, *cplim, *cp;
+ register struct if_msghdr *ifm;
+ register struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ u_long i;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = AF_NS;
+ 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)
+ lookforinterfaces = 0;
+ cplim = buf + needed;
+ for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)cp;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ bzero(&ifs, sizeof(ifs));
+ ifs.int_flags = flags = ifm->ifm_flags | IFF_INTERFACE;
+ if ((flags & IFF_UP) == 0 || no_nsaddr)
+ lookforinterfaces = 1;
+ sdl = (struct sockaddr_dl *) (ifm + 1);
+ sdl->sdl_data[sdl->sdl_nlen] = 0;
+ no_nsaddr = 1;
+ continue;
+ }
+ if (ifm->ifm_type != RTM_NEWADDR)
+ quit("ifinit: out of sync");
+ if ((flags & IFF_UP) == 0)
+ continue;
+ ifam = (struct ifa_msghdr *)ifm;
+ info.rti_addrs = ifam->ifam_addrs;
+ rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
+ if (ifaaddr == 0) {
+ syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
+ continue;
+ }
+ ifs.int_addr = *ifaaddr;
+ if (ifs.int_addr.sa_family != AF_NS)
+ continue;
+ no_nsaddr = 0;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get dstaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ if (brdaddr->sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get broadaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * already known to us?
+ * what makes a POINTOPOINT if unique is its dst addr,
+ * NOT its source address
+ */
+ if ( ((ifs.int_flags & IFF_POINTOPOINT) &&
+ if_ifwithdstaddr(&ifs.int_dstaddr)) ||
+ ( ((ifs.int_flags & IFF_POINTOPOINT) == 0) &&
+ if_ifwithaddr(&ifs.int_addr)))
+ continue;
+ /* no one cares about software loopback interfaces */
+ if (ifs.int_flags & IFF_LOOPBACK)
+ continue;
+ ifp = (struct interface *)
+ malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
+ if (ifp == 0) {
+ syslog(LOG_ERR, "XNSrouted: out of memory\n");
+ lookforinterfaces = 1;
+ break;
+ }
+ *ifp = ifs;
+ /*
+ * Count the # of directly connected networks
+ * and point to point links which aren't looped
+ * back to ourself. This is used below to
+ * decide if we should be a routing ``supplier''.
+ */
+ if ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+ if_ifwithaddr(&ifs.int_dstaddr) == 0)
+ externalinterfaces++;
+ /*
+ * If we have a point-to-point link, we want to act
+ * as a supplier even if it's our only interface,
+ * as that's the only way our peer on the other end
+ * can tell that the link is up.
+ */
+ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+ supplier = 1;
+ ifp->int_name = (char *)(ifp + 1);
+ strcpy(ifp->int_name, sdl->sdl_data);
+ ifp->int_metric = ifam->ifam_metric;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ free(buf);
+}
+
+addrouteforif(ifp)
+ struct interface *ifp;
+{
+ struct sockaddr_ns net;
+ struct sockaddr *dst;
+ int state, metric;
+ struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT) {
+ int (*match)();
+ register struct interface *ifp2 = ifnet;
+ register struct interface *ifprev = ifnet;
+
+ dst = &ifp->int_dstaddr;
+
+ /* Search for interfaces with the same net */
+ ifp->int_sq.n = ifp->int_sq.p = &(ifp->int_sq);
+ match = afswitch[dst->sa_family].af_netmatch;
+ if (match)
+ for (ifp2 = ifnet; ifp2; ifp2 =ifp2->int_next) {
+ if (ifp->int_flags & IFF_POINTOPOINT == 0)
+ continue;
+ if ((*match)(&ifp2->int_dstaddr,&ifp->int_dstaddr)) {
+ insque(&ifp2->int_sq,&ifp->int_sq);
+ break;
+ }
+ }
+ } else {
+ dst = &ifp->int_broadaddr;
+ }
+ rt = rtlookup(dst);
+ if (rt)
+ rtdelete(rt);
+ if (tracing)
+ fprintf(stderr, "Adding route to interface %s\n", ifp->int_name);
+ if (ifp->int_transitions++ > 0)
+ syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+ rtadd(dst, &ifp->int_addr, ifp->int_metric,
+ ifp->int_flags & (IFF_INTERFACE|IFF_PASSIVE|IFF_REMOTE));
+}
+
diff --git a/usr.sbin/XNSrouted/table.h b/usr.sbin/XNSrouted/table.h
new file mode 100644
index 0000000..1de2a95
--- /dev/null
+++ b/usr.sbin/XNSrouted/table.h
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ *
+ * @(#)table.h 5.1 (Berkeley) 6/4/85 (routed/table.h)
+ *
+ * @(#)table.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Routing table structure; differs a bit from kernel tables.
+ *
+ * Note: the union below must agree in the first 4 members
+ * so the ioctl's will work.
+ */
+struct rthash {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+};
+
+#ifdef RTM_ADD
+#define rtentry ortentry
+#endif
+
+struct rt_entry {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+ union {
+ struct rtentry rtu_rt;
+ struct {
+ u_long rtu_hash;
+ struct sockaddr rtu_dst;
+ struct sockaddr rtu_router;
+ short rtu_flags;
+ short rtu_state;
+ int rtu_timer;
+ int rtu_metric;
+ struct interface *rtu_ifp;
+ } rtu_entry;
+ } rt_rtu;
+};
+
+#define rt_rt rt_rtu.rtu_rt /* pass to ioctl */
+#define rt_hash rt_rtu.rtu_entry.rtu_hash /* for net or host */
+#define rt_dst rt_rtu.rtu_entry.rtu_dst /* match value */
+#define rt_router rt_rtu.rtu_entry.rtu_router /* who to forward to */
+#define rt_flags rt_rtu.rtu_entry.rtu_flags /* kernel flags */
+#define rt_timer rt_rtu.rtu_entry.rtu_timer /* for invalidation */
+#define rt_state rt_rtu.rtu_entry.rtu_state /* see below */
+#define rt_metric rt_rtu.rtu_entry.rtu_metric /* cost of route */
+#define rt_ifp rt_rtu.rtu_entry.rtu_ifp /* interface to take */
+
+#define ROUTEHASHSIZ 32 /* must be a power of 2 */
+#define ROUTEHASHMASK (ROUTEHASHSIZ - 1)
+
+/*
+ * "State" of routing table entry.
+ */
+#define RTS_CHANGED 0x1 /* route has been altered recently */
+#define RTS_PASSIVE IFF_PASSIVE /* don't time out route */
+#define RTS_INTERFACE IFF_INTERFACE /* route is for network interface */
+#define RTS_REMOTE IFF_REMOTE /* route is for ``remote'' entity */
+
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+struct rt_entry *rtlookup();
+struct rt_entry *rtfind();
diff --git a/usr.sbin/XNSrouted/tables.c b/usr.sbin/XNSrouted/tables.c
new file mode 100644
index 0000000..4b00dc5
--- /dev/null
+++ b/usr.sbin/XNSrouted/tables.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[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+extern char *xns_ntoa();
+#define FIXLEN(s) { if ((s)->sa_len == 0) (s)->sa_len = sizeof (*(s));}
+
+int install = !DEBUG; /* if 1 call kernel */
+int delete = 1;
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int doinghost = 1;
+
+ if (dst->sa_family >= AF_MAX)
+ return (0);
+ (*afswitch[dst->sa_family].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ goto again;
+ }
+ return (0);
+}
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+struct rt_entry *
+rtfind(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int af = dst->sa_family;
+ int doinghost = 1, (*match)();
+
+ if (af >= AF_MAX)
+ return (0);
+ (*afswitch[af].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (doinghost) {
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ } else {
+ if (rt->rt_dst.sa_family == af &&
+ (*match)(&rt->rt_dst, dst))
+ return (rt);
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ match = afswitch[af].af_netmatch;
+ goto again;
+ }
+ return (0);
+}
+
+rtadd(dst, gate, metric, state)
+ struct sockaddr *dst, *gate;
+ int metric, state;
+{
+ struct afhash h;
+ register struct rt_entry *rt;
+ struct rthash *rh;
+ int af = dst->sa_family, flags;
+ u_int hash;
+
+ FIXLEN(dst);
+ FIXLEN(gate);
+ if (af >= AF_MAX)
+ return;
+ (*afswitch[af].af_hash)(dst, &h);
+ flags = (*afswitch[af].af_ishost)(dst) ? RTF_HOST : 0;
+ if (flags & RTF_HOST) {
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+ } else {
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ }
+ rt = (struct rt_entry *)malloc(sizeof (*rt));
+ if (rt == 0)
+ return;
+ rt->rt_hash = hash;
+ rt->rt_dst = *dst;
+ rt->rt_router = *gate;
+ rt->rt_metric = metric;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ if (metric)
+ rt->rt_flags |= RTF_GATEWAY;
+ insque(rt, rh);
+ TRACE_ACTION(ADD, rt);
+ /*
+ * If the ioctl fails because the gateway is unreachable
+ * from this host, discard the entry. This should only
+ * occur because of an incorrect entry in /etc/gateways.
+ */
+ if (install && rtioctl(ADD, &rt->rt_rt) < 0) {
+ if (errno != EEXIST)
+ perror("SIOCADDRT");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION(DELETE, rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+rtchange(rt, gate, metric)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric;
+{
+ int doioctl = 0, metricchanged = 0;
+ struct rtentry oldroute;
+
+ FIXLEN(gate);
+ if (!equal(&rt->rt_router, gate))
+ doioctl++;
+ if (metric != rt->rt_metric)
+ metricchanged++;
+ if (doioctl || metricchanged) {
+ TRACE_ACTION(CHANGE FROM, rt);
+ if (doioctl) {
+ oldroute = rt->rt_rt;
+ rt->rt_router = *gate;
+ }
+ rt->rt_metric = metric;
+ if ((rt->rt_state & RTS_INTERFACE) && metric) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ syslog(LOG_ERR,
+ "changing route from interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ }
+ if (metric)
+ rt->rt_flags |= RTF_GATEWAY;
+ else
+ rt->rt_flags &= ~RTF_GATEWAY;
+ rt->rt_state |= RTS_CHANGED;
+ TRACE_ACTION(CHANGE TO, rt);
+ }
+ if (doioctl && install) {
+#ifndef RTM_ADD
+ if (rtioctl(ADD, &rt->rt_rt) < 0)
+ syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+ if (delete && rtioctl(DELETE, &oldroute) < 0)
+ perror("rtioctl DELETE");
+#else
+ if (delete == 0) {
+ if (rtioctl(ADD, &rt->rt_rt) >= 0)
+ return;
+ } else {
+ if (rtioctl(CHANGE, &rt->rt_rt) >= 0)
+ return;
+ }
+ syslog(LOG_ERR, "rtioctl ADD dst %s, gw %s: %m",
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_dst)->sns_addr),
+ xns_ntoa(&((struct sockaddr_ns *)&rt->rt_router)->sns_addr));
+#endif
+ }
+}
+
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ struct sockaddr *sa = &(rt->rt_rt.rt_gateway);
+ FIXLEN(sa);
+#undef rt_dst
+ sa = &(rt->rt_rt.rt_dst);
+ FIXLEN(sa);
+ if (rt->rt_state & RTS_INTERFACE) {
+ syslog(LOG_ERR, "deleting route to interface %s (timed out)",
+ rt->rt_ifp->int_name);
+ }
+ TRACE_ACTION(DELETE, rt);
+ if (install && rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtioctl DELETE");
+ remque(rt);
+ free((char *)rt);
+}
+
+rtinit()
+{
+ register struct rthash *rh;
+
+ for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+ for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+}
+int seqno;
+
+rtioctl(action, ort)
+ int action;
+ struct ortentry *ort;
+{
+#ifndef RTM_ADD
+ switch (action) {
+
+ case ADD:
+ return (ioctl(s, SIOCADDRT, (char *)ort));
+
+ case DELETE:
+ return (ioctl(s, SIOCDELRT, (char *)ort));
+
+ default:
+ return (-1);
+ }
+#else /* RTM_ADD */
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr w_dst;
+ struct sockaddr w_gate;
+ struct sockaddr_ns w_netmask;
+ } w;
+#define rtm w.w_rtm
+
+ bzero((char *)&w, sizeof(w));
+ rtm.rtm_msglen = sizeof(w);
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = (action == ADD ? RTM_ADD :
+ (action == DELETE ? RTM_DELETE : RTM_CHANGE));
+#undef rt_flags
+ rtm.rtm_flags = ort->rt_flags;
+ rtm.rtm_seq = ++seqno;
+ rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ bcopy((char *)&ort->rt_dst, (char *)&w.w_dst, sizeof(w.w_dst));
+ bcopy((char *)&ort->rt_gateway, (char *)&w.w_gate, sizeof(w.w_gate));
+ w.w_gate.sa_family = w.w_dst.sa_family = AF_NS;
+ w.w_gate.sa_len = w.w_dst.sa_len = sizeof(w.w_dst);
+ if (rtm.rtm_flags & RTF_HOST) {
+ rtm.rtm_msglen -= sizeof(w.w_netmask);
+ } else {
+ w.w_netmask = ns_netmask;
+ rtm.rtm_msglen -= 8;
+ }
+ errno = 0;
+ return write(r, (char *)&w, rtm.rtm_msglen);
+#endif /* RTM_ADD */
+}
diff --git a/usr.sbin/XNSrouted/timer.c b/usr.sbin/XNSrouted/timer.c
new file mode 100644
index 0000000..32c2bff
--- /dev/null
+++ b/usr.sbin/XNSrouted/timer.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)timer.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+int timeval = -TIMER_RATE;
+
+/*
+ * Timer routine. Performs routing information supply
+ * duties and manages timers on routing table entries.
+ */
+void
+timer()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1, timetobroadcast;
+
+ timeval += TIMER_RATE;
+ if (lookforinterfaces && (timeval % CHECK_INTERVAL) == 0)
+ ifinit();
+ timetobroadcast = supplier && (timeval % SUPPLY_INTERVAL) == 0;
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ /*
+ * We don't advance time on a routing entry for
+ * a passive gateway or that for our only interface.
+ * The latter is excused because we don't act as
+ * a routing information supplier and hence would
+ * time it out. This is fair as if it's down
+ * we're cut off from the world anyway and it's
+ * not likely we'll grow any new hardware in
+ * the mean time.
+ */
+ if (!(rt->rt_state & RTS_PASSIVE) &&
+ (supplier || !(rt->rt_state & RTS_INTERFACE)))
+ rt->rt_timer += TIMER_RATE;
+ if (rt->rt_timer >= EXPIRE_TIME)
+ rt->rt_metric = HOPCNT_INFINITY;
+ if (rt->rt_timer >= GARBAGE_TIME) {
+ rt = rt->rt_back;
+ /* Perhaps we should send a REQUEST for this route? */
+ rtdelete(rt->rt_forw);
+ continue;
+ }
+ if (rt->rt_state & RTS_CHANGED) {
+ rt->rt_state &= ~RTS_CHANGED;
+ /* don't send extraneous packets */
+ if (!supplier || timetobroadcast)
+ continue;
+ msg->rip_cmd = htons(RIPCMD_RESPONSE);
+ msg->rip_nets[0].rip_dst =
+ (satons_addr(rt->rt_dst)).x_net;
+ msg->rip_nets[0].rip_metric =
+ htons(min(rt->rt_metric+1, HOPCNT_INFINITY));
+ toall(sndmsg);
+ }
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (timetobroadcast)
+ toall(supply);
+ alarm(TIMER_RATE);
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+void
+hup()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+ if (supplier) {
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
+ rt->rt_metric = HOPCNT_INFINITY;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ toall(supply);
+ }
+ exit(1);
+}
diff --git a/usr.sbin/XNSrouted/tools/query.c b/usr.sbin/XNSrouted/tools/query.c
new file mode 100644
index 0000000..7deeac0
--- /dev/null
+++ b/usr.sbin/XNSrouted/tools/query.c
@@ -0,0 +1,232 @@
+/*-
+ * Copyright (c) 1983, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code includes software contributed to Berkeley by
+ * Bill Nesheim at Cornell University.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netns/ns.h>
+#include <netns/idp.h>
+#include <errno.h>
+#include <stdio.h>
+#include <netdb.h>
+#include "../protocol.h"
+#define IDPPORT_RIF 1
+
+#define WTIME 5 /* Time to wait for responses */
+
+int s;
+int timedout, timeout();
+char packet[MAXPACKETSIZE];
+extern int errno;
+struct sockaddr_ns myaddr = {sizeof(myaddr), AF_NS};
+char *ns_ntoa();
+struct ns_addr ns_addr();
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int cc, count, bits;
+ struct sockaddr from;
+ int fromlen = sizeof(from);
+ struct timeval notime;
+
+ if (argc < 2) {
+ printf("usage: query hosts...\n");
+ exit(1);
+ }
+ s = getsocket(SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+
+ argv++, argc--;
+ query(argv,argc);
+
+ /*
+ * Listen for returning packets;
+ * may be more than one packet per host.
+ */
+ bits = 1 << s;
+ bzero(&notime, sizeof(notime));
+ signal(SIGALRM, timeout);
+ alarm(WTIME);
+ while (!timedout ||
+ select(20, &bits, 0, 0, &notime) > 0) {
+ struct nspacket {
+ struct idp hdr;
+ char data[512];
+ } response;
+ cc = recvfrom(s, &response, sizeof (response), 0,
+ &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("recvfrom");
+ (void) close(s);
+ exit(1);
+ }
+ continue;
+ }
+ rip_input(&from, response.data, cc);
+ count--;
+ }
+}
+static struct sockaddr_ns router = {sizeof(myaddr), AF_NS};
+static struct ns_addr zero_addr;
+static short allones[] = {-1, -1, -1};
+
+query(argv,argc)
+char **argv;
+{
+ register struct rip *msg = (struct rip *)packet;
+ char *host = *argv;
+ int flags = 0;
+ struct ns_addr specific;
+
+ if (bcmp(*argv, "-r", 3) == 0) {
+ flags = MSG_DONTROUTE; argv++; argc--;
+ }
+ host = *argv;
+ router.sns_addr = ns_addr(host);
+ router.sns_addr.x_port = htons(IDPPORT_RIF);
+ if (ns_hosteq(zero_addr, router.sns_addr)) {
+ router.sns_addr.x_host = *(union ns_host *) allones;
+ }
+ msg->rip_cmd = htons(RIPCMD_REQUEST);
+ msg->rip_nets[0].rip_dst = *(union ns_net *) allones;
+ msg->rip_nets[0].rip_metric = htons(HOPCNT_INFINITY);
+ if (argc > 0) {
+ specific = ns_addr(*argv);
+ msg->rip_nets[0].rip_dst = specific.x_net;
+ specific.x_host = zero_addr.x_host;
+ specific.x_port = zero_addr.x_port;
+ printf("Net asked for was %s\n", ns_ntoa(specific));
+ }
+ if (sendto(s, packet, sizeof (struct rip), flags,
+ &router, sizeof(router)) < 0)
+ perror(host);
+}
+
+/*
+ * Handle an incoming routing packet.
+ */
+rip_input(from, msg, size)
+ struct sockaddr_ns *from;
+ register struct rip *msg;
+ int size;
+{
+ struct netinfo *n;
+ char *name;
+ int lna, net, subnet;
+ struct hostent *hp;
+ struct netent *np;
+ static struct ns_addr work;
+
+ if (htons(msg->rip_cmd) != RIPCMD_RESPONSE)
+ return;
+ printf("from %s\n", ns_ntoa(from->sns_addr));
+ size -= sizeof (struct idp);
+ size -= sizeof (short);
+ n = msg->rip_nets;
+ while (size > 0) {
+ union ns_net_u net;
+ if (size < sizeof (struct netinfo))
+ break;
+ net.net_e = n->rip_dst;
+ printf("\t%d, metric %d\n", ntohl(net.long_e),
+ ntohs(n->rip_metric));
+ size -= sizeof (struct netinfo), n++;
+ }
+}
+
+timeout()
+{
+ timedout = 1;
+}
+getsocket(type, proto)
+ int type, proto;
+{
+ struct sockaddr_ns *sns = &myaddr;
+ int domain = sns->sns_family;
+ int retry, s, on = 1;
+
+ retry = 1;
+ while ((s = socket(domain, type, proto)) < 0 && retry) {
+ perror("socket");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ while (bind(s, sns, sizeof (*sns), 0) < 0 && retry) {
+ perror("bind");
+ sleep(5 * retry);
+ retry <<= 1;
+ }
+ if (retry == 0)
+ return (-1);
+ if (domain==AF_NS) {
+ struct idp idp;
+ if (setsockopt(s, 0, SO_HEADERS_ON_INPUT, &on, sizeof(on))) {
+ perror("setsockopt SEE HEADERS");
+ exit(1);
+ }
+ idp.idp_pt = NSPROTO_RI;
+ if (setsockopt(s, 0, SO_DEFAULT_HEADERS, &idp, sizeof(idp))) {
+ perror("setsockopt SET HEADERS");
+ exit(1);
+ }
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ perror("setsockopt SO_BROADCAST");
+ exit(1);
+ }
+ return (s);
+}
diff --git a/usr.sbin/XNSrouted/trace.c b/usr.sbin/XNSrouted/trace.c
new file mode 100644
index 0000000..385bb9b
--- /dev/null
+++ b/usr.sbin/XNSrouted/trace.c
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define RIPCMDS
+#include <stdlib.h>
+#include "defs.h"
+
+#define NRECORDS 50 /* size of circular trace buffer */
+#ifdef DEBUG
+FILE *ftrace = stdout;
+int tracing = 1;
+#else DEBUG
+FILE *ftrace = NULL;
+int tracing = 0;
+#endif
+
+char *xns_ntoa();
+
+traceinit(ifp)
+ register struct interface *ifp;
+{
+ static int iftraceinit();
+
+ if (iftraceinit(ifp, &ifp->int_input) &&
+ iftraceinit(ifp, &ifp->int_output))
+ return;
+ tracing = 0;
+ syslog(LOG_ERR, "traceinit: can't init %s\n", ifp->int_name);
+}
+
+static
+iftraceinit(ifp, ifd)
+ struct interface *ifp;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+
+ ifd->ifd_records =
+ (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
+ if (ifd->ifd_records == 0)
+ return (0);
+ ifd->ifd_front = ifd->ifd_records;
+ ifd->ifd_count = 0;
+ for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
+ t->ift_size = 0;
+ t->ift_packet = 0;
+ }
+ ifd->ifd_if = ifp;
+ return (1);
+}
+
+traceon(file)
+ char *file;
+{
+
+ if (ftrace != NULL)
+ return;
+ ftrace = fopen(file, "a");
+ if (ftrace == NULL)
+ return;
+ dup2(fileno(ftrace), 1);
+ dup2(fileno(ftrace), 2);
+ tracing = 1;
+}
+
+traceoff()
+{
+ if (!tracing)
+ return;
+ if (ftrace != NULL)
+ fclose(ftrace);
+ ftrace = NULL;
+ tracing = 0;
+}
+
+trace(ifd, who, p, len, m)
+ register struct ifdebug *ifd;
+ struct sockaddr *who;
+ char *p;
+ int len, m;
+{
+ register struct iftrace *t;
+
+ if (ifd->ifd_records == 0)
+ return;
+ t = ifd->ifd_front++;
+ if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
+ ifd->ifd_front = ifd->ifd_records;
+ if (ifd->ifd_count < NRECORDS)
+ ifd->ifd_count++;
+ if (t->ift_size > 0 && t->ift_packet)
+ free(t->ift_packet);
+ t->ift_packet = 0;
+ t->ift_stamp = time(0);
+ t->ift_who = *who;
+ if (len > 0) {
+ t->ift_packet = malloc(len);
+ if (t->ift_packet)
+ bcopy(p, t->ift_packet, len);
+ else
+ len = 0;
+ }
+ t->ift_size = len;
+ t->ift_metric = m;
+}
+
+traceaction(fd, action, rt)
+ FILE *fd;
+ char *action;
+ struct rt_entry *rt;
+{
+ struct sockaddr_ns *dst, *gate;
+ static struct bits {
+ int t_bits;
+ char *t_name;
+ } flagbits[] = {
+ { RTF_UP, "UP" },
+ { RTF_GATEWAY, "GATEWAY" },
+ { RTF_HOST, "HOST" },
+ { 0 }
+ }, statebits[] = {
+ { RTS_PASSIVE, "PASSIVE" },
+ { RTS_REMOTE, "REMOTE" },
+ { RTS_INTERFACE,"INTERFACE" },
+ { RTS_CHANGED, "CHANGED" },
+ { 0 }
+ };
+ register struct bits *p;
+ register int first;
+ char *cp;
+ struct interface *ifp;
+
+ if (fd == NULL)
+ return;
+ fprintf(fd, "%s ", action);
+ dst = (struct sockaddr_ns *)&rt->rt_dst;
+ gate = (struct sockaddr_ns *)&rt->rt_router;
+ fprintf(fd, "dst %s, ", xns_ntoa(&dst->sns_addr));
+ fprintf(fd, "router %s, metric %d, flags",
+ xns_ntoa(&gate->sns_addr), rt->rt_metric);
+ cp = " %s";
+ for (first = 1, p = flagbits; p->t_bits > 0; p++) {
+ if ((rt->rt_flags & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ fprintf(fd, " state");
+ cp = " %s";
+ for (first = 1, p = statebits; p->t_bits > 0; p++) {
+ if ((rt->rt_state & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ putc('\n', fd);
+ if (!tracepackets && (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+ dumpif(fd, rt->rt_ifp);
+ fflush(fd);
+}
+
+dumpif(fd, ifp)
+ register struct interface *ifp;
+ FILE *fd;
+{
+ if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+ fprintf(fd, "*** Packet history for interface %s ***\n",
+ ifp->int_name);
+ dumptrace(fd, "to", &ifp->int_output);
+ dumptrace(fd, "from", &ifp->int_input);
+ fprintf(fd, "*** end packet history ***\n");
+ }
+}
+
+dumptrace(fd, dir, ifd)
+ FILE *fd;
+ char *dir;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+ char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+
+ if (ifd->ifd_front == ifd->ifd_records &&
+ ifd->ifd_front->ift_size == 0) {
+ fprintf(fd, "%s: no packets.\n", cp);
+ return;
+ }
+ fprintf(fd, "%s trace:\n", cp);
+ t = ifd->ifd_front - ifd->ifd_count;
+ if (t < ifd->ifd_records)
+ t += NRECORDS;
+ for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
+ if (t >= ifd->ifd_records + NRECORDS)
+ t = ifd->ifd_records;
+ if (t->ift_size == 0)
+ continue;
+ fprintf(fd, "%.24s: metric=%d\n", ctime(&t->ift_stamp),
+ t->ift_metric);
+ dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size);
+ }
+}
+
+dumppacket(fd, dir, who, cp, size)
+ FILE *fd;
+ struct sockaddr_ns *who; /* should be sockaddr */
+ char *dir, *cp;
+ register int size;
+{
+ register struct rip *msg = (struct rip *)cp;
+ register struct netinfo *n;
+ char *xns_nettoa();
+
+ if (msg->rip_cmd && ntohs(msg->rip_cmd) < RIPCMD_MAX)
+ fprintf(fd, "%s %s %s#%x", ripcmds[ntohs(msg->rip_cmd)],
+ dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %s#%x\n", ntohs(msg->rip_cmd),
+ dir, xns_ntoa(&who->sns_addr), ntohs(who->sns_addr.x_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet);
+ return;
+ }
+ switch (ntohs(msg->rip_cmd)) {
+
+ case RIPCMD_REQUEST:
+ case RIPCMD_RESPONSE:
+ fprintf(fd, ":\n");
+ size -= sizeof (u_short);
+ n = msg->rip_nets;
+ for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+ if (size < sizeof (struct netinfo))
+ break;
+ fprintf(fd, "\tnet %s metric %d\n",
+ xns_nettoa(n->rip_dst),
+ ntohs(n->rip_metric));
+ }
+ break;
+
+ }
+}
+
+union ns_net_u net;
+
+char *
+xns_nettoa(val)
+union ns_net val;
+{
+ static char buf[100];
+ net.net_e = val;
+ (void)sprintf(buf, "%lx", ntohl(net.long_e));
+ return (buf);
+}
+
+
+char *
+xns_ntoa(addr)
+struct ns_addr *addr;
+{
+ static char buf[100];
+
+ (void)sprintf(buf, "%s#%x:%x:%x:%x:%x:%x",
+ xns_nettoa(addr->x_net),
+ addr->x_host.c_host[0], addr->x_host.c_host[1],
+ addr->x_host.c_host[2], addr->x_host.c_host[3],
+ addr->x_host.c_host[4], addr->x_host.c_host[5]);
+
+ return(buf);
+}
diff --git a/usr.sbin/XNSrouted/trace.h b/usr.sbin/XNSrouted/trace.h
new file mode 100644
index 0000000..b7cf3a8
--- /dev/null
+++ b/usr.sbin/XNSrouted/trace.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This file includes significant work done at Cornell University by
+ * Bill Nesheim. That work included by permission.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)trace.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Xerox Routing Information Protocol.
+ */
+
+/*
+ * Trace record format.
+ */
+struct iftrace {
+ time_t ift_stamp; /* time stamp */
+ struct sockaddr ift_who; /* from/to */
+ char *ift_packet; /* pointer to packet */
+ short ift_size; /* size of packet */
+ short ift_metric; /* metric */
+};
+
+/*
+ * Per interface packet tracing buffers. An incoming and
+ * outgoing circular buffer of packets is maintained, per
+ * interface, for debugging. Buffers are dumped whenever
+ * an interface is marked down.
+ */
+struct ifdebug {
+ struct iftrace *ifd_records; /* array of trace records */
+ struct iftrace *ifd_front; /* next empty trace record */
+ int ifd_count; /* number of unprinted records */
+ struct interface *ifd_if; /* for locating stuff */
+};
+
+/*
+ * Packet tracing stuff.
+ */
+int tracepackets; /* watch packets as they go by */
+int tracing; /* on/off */
+FILE *ftrace; /* output trace file */
+
+#define TRACE_ACTION(action, route) { \
+ if (tracing) \
+ traceaction(ftrace, "action", route); \
+ }
+#define TRACE_INPUT(ifp, src, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(src); \
+ if (ifp) \
+ trace(&ifp->int_input, src, &packet[sizeof(struct idp)], size, \
+ ntohl(ifp->int_metric)); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "from", src, &packet[sizeof(struct idp)], size); \
+ }
+#define TRACE_OUTPUT(ifp, dst, size) { \
+ if (tracing) { \
+ ifp = if_iflookup(dst); \
+ if (ifp) \
+ trace(&ifp->int_output, dst, &packet[sizeof(struct idp)], size, ifp->int_metric); \
+ } \
+ if (tracepackets && ftrace) \
+ dumppacket(ftrace, "to", dst, &packet[sizeof(struct idp)], size); \
+ }
diff --git a/usr.sbin/ac/Makefile b/usr.sbin/ac/Makefile
new file mode 100644
index 0000000..349e9ce
--- /dev/null
+++ b/usr.sbin/ac/Makefile
@@ -0,0 +1,18 @@
+# $Id: Makefile,v 1.1.1.1 1994/05/18 08:00:44 csgr Exp $
+
+PROG= ac
+MAN8= 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 0000000..3c34716
--- /dev/null
+++ b/usr.sbin/ac/ac.8
@@ -0,0 +1,155 @@
+.\"
+.\" 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 1994/05/18 08:00:45 csgr Exp $
+.\"
+.Dd March 15, 1994
+.Dt AC 8
+.Os
+.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
+.\" .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 0000000..2d68315
--- /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 1994/05/18 08:00:45 csgr 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 0000000..8e3f336
--- /dev/null
+++ b/usr.sbin/accton/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= accton
+MAN8= 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 0000000..00c8fa7
--- /dev/null
+++ b/usr.sbin/accton/accton.8
@@ -0,0 +1,22 @@
+.TH ACCTON 1 "21 May 1993"
+.SH NAME
+.\" accton \- system accounting
+accton \- system accounting
+.SH SYNOPSIS
+accton [\fIfile\fR]
+.SH DESCRIPTION
+.B accton
+is a command for switching system accounting on or off.
+If called with \fIfile\fR system accounting is turned on and
+for every executed command a record is stored in \fIfile\fR.
+If called without an argument accounting is turned off.
+
+.SH FILES
+.TP 20
+/var/account/*
+normal place for the accounting files.
+.SH SEE ALSO
+
+.IR acct (2),
+.IR sa (8).
+
diff --git a/usr.sbin/accton/accton.c b/usr.sbin/accton/accton.c
new file mode 100644
index 0000000..c65ef68
--- /dev/null
+++ b/usr.sbin/accton/accton.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)accton.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ switch(argc) {
+ case 0:
+ if (acct(NULL)) {
+ (void)fprintf(stderr,
+ "accton: %s\n", strerror(errno));
+ exit(1);
+ }
+ break;
+ case 1:
+ if (acct(*argv)) {
+ (void)fprintf(stderr,
+ "accton: %s: %s\n", *argv, strerror(errno));
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: accton [file]\n");
+ exit(1);
+}
diff --git a/usr.sbin/amd/Makefile b/usr.sbin/amd/Makefile
new file mode 100644
index 0000000..96405b8
--- /dev/null
+++ b/usr.sbin/amd/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= amd amq fsinfo mk-amd-map
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/amd/amd/ChangeLog b/usr.sbin/amd/amd/ChangeLog
new file mode 100644
index 0000000..2cd1807
--- /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 0000000..a5023c0
--- /dev/null
+++ b/usr.sbin/amd/amd/Makefile
@@ -0,0 +1,32 @@
+# @(#)Makefile 8.2 (Berkeley) 4/22/94
+
+PROG= amd
+MAN8= amd.8
+OS= bsd44
+SRCS= afs_ops.c am_ops.c clock.c util.c xutil.c \
+ efs_ops.c mapc.c info_file.c info_hes.c \
+ info_ndbm.c info_passwd.c info_nis.c \
+ info_union.c map.c srvr_afs.c srvr_nfs.c \
+ mntfs.c misc_rpc.c mount_fs.c mount_xdr.c \
+ mtab.c mtab_bsd.c nfs_ops.c nfs_prot_svc.c \
+ nfs_start.c nfs_subr.c nfs_prot_xdr.c opts.c \
+ pfs_ops.c rpc_fwd.c sched.c sfs_ops.c amq_svc.c \
+ amq_subr.c umount_fs.c host_ops.c nfsx_ops.c \
+ ufs_ops.c ifs_ops.c amd.c get_args.c restart.c wire.c
+OBJS+= vers.${PROG}.o
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-DARCH_REP=\"${MACHINE}\"
+CFLAGS+=-DOS_REP=\"${OS}\"
+CFLAGS+=-DOS_HDR=\"os-${OS}.h\"
+CFLAGS+=${CONFIG}
+CLEANFILES+=vers.${PROG}.c vers.${PROG}.o version.amd
+
+vers.${PROG}.c: ${SRCS:.c=.o}
+ @d=${.CURDIR}/ sh ${.CURDIR}/../config/newvers.sh ${PROG} ${MACHINE} ${OS}
+
+.PATH: ${.CURDIR}/../rpcx ${.CURDIR}/../config
+.include "Makefile.config"
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/amd/afs_ops.c b/usr.sbin/amd/amd/afs_ops.c
new file mode 100644
index 0000000..6dfdc14
--- /dev/null
+++ b/usr.sbin/amd/amd/afs_ops.c
@@ -0,0 +1,1816 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)afs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: afs_ops.c,v 5.2.2.4 1992/05/31 16:36:36 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#define NFS
+#define NFSCLIENT
+
+#include <sys/stat.h>
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Automount file system
+ * Direct file system
+ * Root file system
+ * Top-level file system
+ */
+
+/*
+ * Interval between forced retries of a mount.
+ */
+#define RETRY_INTERVAL 2
+
+/*
+ * AFS needs nothing in particular.
+ */
+static char *afs_match P((am_opts *fo));
+static char *afs_match(fo)
+am_opts *fo;
+{
+ char *p = fo->opt_rfs;
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "auto: no mount point named (rfs:=)");
+ return 0;
+ }
+ if (!fo->opt_fs) {
+ plog(XLOG_USER, "auto: no map named (fs:=)");
+ return 0;
+ }
+ /*
+ * Swap round fs:= and rfs:= options
+ * ... historical (jsp)
+ */
+ fo->opt_rfs = fo->opt_fs;
+ fo->opt_fs = p;
+ /*
+ * mtab entry turns out to be the name of the mount map
+ */
+ return strdup(fo->opt_rfs ? fo->opt_rfs : ".");
+}
+
+/*
+ * Mount an automounter directory.
+ * The automounter is connected into the system
+ * as a user-level NFS server. mount_toplvl constructs
+ * the necessary NFS parameters to be given to the
+ * kernel so that it will talk back to us.
+ */
+static int mount_toplvl P((char *dir, char *opts));
+static int mount_toplvl(dir, opts)
+char *dir;
+char *opts;
+{
+ struct nfs_args nfs_args;
+ struct mntent mnt;
+ int retry;
+ struct sockaddr_in sin;
+ unsigned short port;
+ int flags;
+ extern nfs_fh *root_fh();
+ nfs_fh *fhp;
+ char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
+
+ MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */
+
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = pid_fsname;
+ mnt.mnt_type = MNTTYPE_AUTO;
+ mnt.mnt_opts = opts;
+ mnt.mnt_freq = 0;
+ mnt.mnt_passno = 0;
+
+ retry = hasmntval(&mnt, "retry");
+ if (retry <= 0)
+ retry = 2; /* XXX */
+
+ /*
+ * get fhandle of remote path for automount point
+ */
+
+ fhp = root_fh(dir);
+ if (!fhp) {
+ plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
+ return EINVAL;
+ }
+
+ NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp);
+
+ /*
+ * Create sockaddr to point to the local machine. 127.0.0.1
+ * is not used since that will not work in HP-UX clusters and
+ * this is no more expensive.
+ */
+ bzero((voidp) &sin, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr = myipaddr;
+ if (port = hasmntval(&mnt, "port")) {
+ sin.sin_port = htons(port);
+ } else {
+ plog(XLOG_ERROR, "no port number specified for %s", dir);
+ return EINVAL;
+ }
+
+ /*
+ * set mount args
+ */
+ NFS_SA_DREF(nfs_args, &sin);
+
+ /*
+ * Make a ``hostname'' string for the kernel
+ */
+#ifndef HOSTNAMESZ
+#define SHORT_MOUNT_NAME
+#endif /* HOSTNAMESZ */
+#ifdef SHORT_MOUNT_NAME
+ sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid());
+#else
+ sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir);
+#endif /* SHORT_MOUNT_NAME */
+ nfs_args.hostname = fs_hostname;
+ nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+ /*
+ * Most kernels have a name length restriction.
+ */
+ if (strlen(fs_hostname) >= HOSTNAMESZ)
+ strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+#ifdef NFSMNT_DUMBTIMR
+ nfs_args.flags |= NFSMNT_DUMBTIMR;
+ plog(XLOG_INFO, "defeating nfs window computation");
+#endif
+
+ /*
+ * Parse a subset of the standard nfs options. The
+ * others are probably irrelevant for this application
+ */
+ if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+ nfs_args.flags |= NFSMNT_TIMEO;
+
+ if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+ nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+ if (nfs_args.biods = hasmntval(&mnt, "biods"))
+ nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
+ /*
+ * Don't cache attributes - they are changing under
+ * the kernel's feet...
+ */
+ nfs_args.acregmin = nfs_args.acregmax = 1;
+ nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
+#endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */
+ /*
+ * These two are constructed internally by the calling routine
+ */
+ if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+ nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef MNTOPT_INTR
+ if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+ nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+ flags = compute_mount_flags(&mnt);
+#ifdef ULTRIX_HACK
+ nfs_args.gfs_flags = flags;
+ flags &= M_RDONLY;
+ if (flags & M_RDONLY)
+ nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+ return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+}
+
+static void afs_mkcacheref P((mntfs *mf));
+static void afs_mkcacheref(mf)
+mntfs *mf;
+{
+ /*
+ * Build a new map cache for this node, or re-use
+ * an existing cache for the same map.
+ */
+ char *cache;
+ if (mf->mf_fo && mf->mf_fo->opt_cache)
+ cache = mf->mf_fo->opt_cache;
+ else
+ cache = "none";
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);
+ mf->mf_prfree = mapc_free;
+}
+
+/*
+ * Mount the root...
+ */
+static int root_mount P((am_node *mp));
+static int root_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ mf->mf_mount = strealloc(mf->mf_mount, pid_fsname);
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, "");
+ mf->mf_prfree = mapc_free;
+
+ return 0;
+}
+
+/*
+ * Mount a sub-mount
+ */
+static int afs_mount P((am_node *mp));
+static int afs_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * Pseudo-directories are used to provide some structure
+ * to the automounted directories instead
+ * of putting them all in the top-level automount directory.
+ *
+ * Here, just increment the parent's link count.
+ */
+ mp->am_parent->am_fattr.nlink++;
+ /*
+ * Info field of . means use parent's info field.
+ * Historical - not documented.
+ */
+ if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
+ mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
+ /*
+ * Compute prefix:
+ *
+ * If there is an option prefix then use that else
+ * If the parent had a prefix then use that with name
+ * of this node appended else
+ * Use the name of this node.
+ *
+ * That means if you want no prefix you must say so
+ * in the map.
+ */
+ if (mf->mf_fo->opt_pref) {
+ /*
+ * the prefix specified as an option
+ */
+ mp->am_pref = strdup(mf->mf_fo->opt_pref);
+ } else {
+ /*
+ * else the parent's prefix
+ * followed by the name
+ * followed by /
+ */
+ char *ppref = mp->am_parent->am_pref;
+ if (ppref == 0)
+ ppref = "";
+ mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
+ }
+
+ /*
+ * Attach a map cache
+ */
+ afs_mkcacheref(mf);
+
+ return 0;
+}
+
+/*
+ * Mount the top-level
+ */
+static int toplvl_mount P((am_node *mp));
+static int toplvl_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ struct stat stb;
+ char opts[256];
+ int error;
+ char *mnttype;
+
+ /*
+ * Mounting the automounter.
+ * Make sure the mount directory exists, construct
+ * the mount options and call the mount_toplvl routine.
+ */
+
+ if (stat(mp->am_path, &stb) < 0) {
+ return errno;
+ } else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
+ return ENOTDIR;
+ }
+
+ if (mf->mf_ops == &toplvl_ops) mnttype = "indirect";
+ else if (mf->mf_ops == &dfs_ops) mnttype = "direct";
+#ifdef HAS_UNION_FS
+ else if (mf->mf_ops == &union_ops) mnttype = "union";
+#endif
+ else mnttype = "auto";
+
+ /*
+ * Construct some mount options
+ */
+ sprintf(opts,
+#ifdef MNTOPT_INTR
+ "%s,%s,%s=%d,%s=%d,%s=%d,%s",
+ MNTOPT_INTR,
+#else
+ "%s,%s=%d,%s=%d,%s=%d,%s",
+#endif /* MNTOPT_INTR */
+ "rw",
+ "port", nfs_port,
+ "timeo", afs_timeo,
+ "retrans", afs_retrans,
+ mnttype);
+
+ error = mount_toplvl(mf->mf_mount, opts);
+ if (error) {
+ errno = error;
+ plog(XLOG_FATAL, "mount_toplvl: %m");
+ return error;
+ }
+
+ return 0;
+}
+
+static void toplvl_mounted P((mntfs *mf));
+static void toplvl_mounted(mf)
+mntfs *mf;
+{
+ afs_mkcacheref(mf);
+}
+
+#ifdef HAS_UNION_FS
+/*
+ * Create a reference to a union'ed entry
+ */
+static int create_union_node P((char *dir, voidp arg));
+static int create_union_node(dir, arg)
+char *dir;
+voidp arg;
+{
+ if (strcmp(dir, "/defaults") != 0) {
+ int error = 0;
+ (void) toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE);
+ if (error > 0) {
+ errno = error; /* XXX */
+ plog(XLOG_ERROR, "Could not mount %s: %m", dir);
+ }
+ return error;
+ }
+ return 0;
+}
+
+static void union_mounted P((mntfs *mf));
+static void union_mounted(mf)
+mntfs *mf;
+{
+ int i;
+
+ afs_mkcacheref(mf);
+
+ /*
+ * Having made the union mount point,
+ * populate all the entries...
+ */
+ for (i = 0; i <= last_used_map; i++) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt == mf) {
+ /* return value from create_union_node is ignored by mapc_keyiter */
+ (void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private,
+ (void (*)P((char*,void*))) create_union_node, mp);
+ break;
+ }
+ }
+
+#ifdef notdef
+ /*
+ * would be nice to flush most of the cache, but we need to
+ * keep the wildcard and /defaults entries...
+ */
+ mapc_free(mf->mf_private);
+ mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc");
+/* mapc_add_kv(mf->mf_private, strdup("/defaults"),
+ strdup("type:=link;opts:=nounmount;sublink:=${key}")); */
+#endif
+}
+#endif /* HAS_UNION_FS */
+
+/*
+ * Unmount an automount sub-node
+ */
+static int afs_umount P((am_node *mp));
+static int afs_umount(mp)
+am_node *mp;
+{
+ return 0;
+}
+
+/*
+ * Unmount a top-level automount node
+ */
+static int toplvl_umount P((am_node *mp));
+static int toplvl_umount(mp)
+am_node *mp;
+{
+ int error;
+
+ struct stat stb;
+again:
+ /*
+ * The lstat is needed if this mount is type=direct.
+ * When that happens, the kernel cache gets confused
+ * between the underlying type (dir) and the mounted
+ * type (link) and so needs to be re-synced before
+ * the unmount. This is all because the unmount system
+ * call follows links and so can't actually unmount
+ * a link (stupid!). It was noted that doing an ls -ld
+ * of the mount point to see why things were not working
+ * actually fixed the problem - so simulate an ls -ld here.
+ */
+ if (lstat(mp->am_path, &stb) < 0) {
+#ifdef DEBUG
+ dlog("lstat(%s): %m", mp->am_path);
+#endif /* DEBUG */
+ }
+ error = UMOUNT_FS(mp->am_path);
+ if (error == EBUSY) {
+ plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
+ sleep(1); /* XXX */
+ goto again;
+ }
+
+ return error;
+}
+
+/*
+ * Unmount an automount node
+ */
+static void afs_umounted P((am_node *mp));
+static void afs_umounted(mp)
+am_node *mp;
+{
+ /*
+ * If this is a pseudo-directory then just adjust the link count
+ * in the parent, otherwise call the generic unmount routine
+ */
+ if (mp->am_parent && mp->am_parent->am_parent)
+ --mp->am_parent->am_fattr.nlink;
+}
+
+/*
+ * Mounting a file system may take a significant period of time. The
+ * problem is that if this is done in the main process thread then
+ * the entire automounter could be blocked, possibly hanging lots of
+ * processes on the system. Instead we use a continuation scheme to
+ * allow mounts to be attempted in a sub-process. When the sub-process
+ * exits we pick up the exit status (by convention a UN*X error number)
+ * and continue in a notifier. The notifier gets handed a data structure
+ * and can then determine whether the mount was successful or not. If
+ * not, it updates the data structure and tries again until there are no
+ * more ways to try the mount, or some other permanent error occurs.
+ * In the mean time no RPC reply is sent, even after the mount is succesful.
+ * We rely on the RPC retry mechanism to resend the lookup request which
+ * can then be handled.
+ */
+
+
+struct continuation {
+ char **ivec; /* Current mount info */
+ am_node *mp; /* Node we are trying to mount */
+ char *key; /* Map key */
+ char *info; /* Info string */
+ char **xivec; /* Saved strsplit vector */
+ char *auto_opts; /* Automount options */
+ am_opts fs_opts; /* Filesystem options */
+ char *def_opts; /* Default automount options */
+ int retry; /* Try again? */
+ int tried; /* Have we tried any yet? */
+ time_t start; /* Time we started this mount */
+ int callout; /* Callout identifier */
+};
+
+#define IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)
+
+/*
+ * Discard an old continuation
+ */
+static void free_continuation P((struct continuation *cp));
+static void free_continuation(cp)
+struct continuation *cp;
+{
+ if (cp->callout)
+ untimeout(cp->callout);
+ free((voidp) cp->key);
+ free((voidp) cp->xivec);
+ free((voidp) cp->info);
+ free((voidp) cp->auto_opts);
+ free((voidp) cp->def_opts);
+ free_opts(&cp->fs_opts);
+ free((voidp) cp);
+}
+
+static int afs_bgmount P((struct continuation*, int));
+
+/*
+ * Discard the underlying mount point and replace
+ * with a reference to an error filesystem.
+ */
+static void assign_error_mntfs P((am_node *mp));
+static void assign_error_mntfs(mp)
+am_node *mp;
+{
+ if (mp->am_error > 0) {
+ /*
+ * Save the old error code
+ */
+ int error = mp->am_error;
+ if (error <= 0)
+ error = mp->am_mnt->mf_error;
+ /*
+ * Discard the old filesystem
+ */
+ free_mntfs(mp->am_mnt);
+ /*
+ * Allocate a new error reference
+ */
+ mp->am_mnt = new_mntfs();
+ /*
+ * Put back the error code
+ */
+ mp->am_mnt->mf_error = error;
+ mp->am_mnt->mf_flags |= MFF_ERROR;
+ /*
+ * Zero the error in the mount point
+ */
+ mp->am_error = 0;
+ }
+}
+
+/*
+ * The continuation function. This is called by
+ * the task notifier when a background mount attempt
+ * completes.
+ */
+static void afs_cont P((int rc, int term, voidp closure));
+static void afs_cont(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ struct continuation *cp = (struct continuation *) closure;
+ mntfs *mf = cp->mp->am_mnt;
+
+ /*
+ * Definitely not trying to mount at the moment
+ */
+ mf->mf_flags &= ~MFF_MOUNTING;
+ /*
+ * While we are mounting - try to avoid race conditions
+ */
+ new_ttl(cp->mp);
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+
+ /*
+ * Check for termination signal or exit status...
+ */
+ if (rc || term) {
+ am_node *xmp;
+
+ if (term) {
+ /*
+ * Not sure what to do for an error code.
+ */
+ mf->mf_error = EIO; /* XXX ? */
+ mf->mf_flags |= MFF_ERROR;
+ plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
+ } else {
+ /*
+ * Check for exit status...
+ */
+ mf->mf_error = rc;
+ mf->mf_flags |= MFF_ERROR;
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
+ }
+
+ /*
+ * If we get here then that attempt didn't work, so
+ * move the info vector pointer along by one and
+ * call the background mount routine again
+ */
+ amd_stats.d_merr++;
+ cp->ivec++;
+ xmp = cp->mp;
+ (void) afs_bgmount(cp, 0);
+ assign_error_mntfs(xmp);
+ } else {
+ /*
+ * The mount worked.
+ */
+ am_mounted(cp->mp);
+ free_continuation(cp);
+ }
+
+ reschedule_timeout_mp();
+}
+
+/*
+ * Retry a mount
+ */
+/*ARGSUSED*/
+static void afs_retry P((int rc, int term, voidp closure));
+static void afs_retry(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ struct continuation *cp = (struct continuation *) closure;
+ int error = 0;
+
+#ifdef DEBUG
+ dlog("Commencing retry for mount of %s", cp->mp->am_path);
+#endif /* DEBUG */
+
+ new_ttl(cp->mp);
+
+ if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
+ /*
+ * The entire mount has timed out.
+ * Set the error code and skip past
+ * all the info vectors so that
+ * afs_bgmount will not have any more
+ * ways to try the mount, so causing
+ * an error.
+ */
+ plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
+ error = ETIMEDOUT;
+ while (*cp->ivec)
+ cp->ivec++;
+ }
+
+ if (error || !IN_PROGRESS(cp)) {
+ (void) afs_bgmount(cp, error);
+ }
+ reschedule_timeout_mp();
+}
+
+/*
+ * Try to mount a file system. Can be called
+ * directly or in a sub-process by run_task
+ */
+static int try_mount P((voidp mvp));
+static int try_mount(mvp)
+voidp mvp;
+{
+ /*
+ * Mount it!
+ */
+ int error;
+ am_node *mp = (am_node *) mvp;
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * If the directory is not yet made and
+ * it needs to be made, then make it!
+ * This may be run in a backgroun process
+ * in which case the flag setting won't be
+ * noticed later - but it is set anyway
+ * just after run_task is called. It
+ * should probably go away totally...
+ */
+ if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) {
+ error = mkdirs(mf->mf_mount, 0555);
+ if (!error)
+ mf->mf_flags |= MFF_MKMNT;
+ }
+
+ error = mount_node(mp);
+#ifdef DEBUG
+ if (error > 0) {
+ errno = error;
+ dlog("afs call to mount_node failed: %m");
+ }
+#endif /* DEBUG */
+ return error;
+}
+
+/*
+ * Pick a file system to try mounting and
+ * do that in the background if necessary
+ *
+For each location:
+ if it is new -defaults then
+ extract and process
+ continue;
+ fi
+ if it is a cut then
+ if a location has been tried then
+ break;
+ fi
+ continue;
+ fi
+ parse mount location
+ discard previous mount location if required
+ find matching mounted filesystem
+ if not applicable then
+ this_error = No such file or directory
+ continue
+ fi
+ if the filesystem failed to be mounted then
+ this_error = error from filesystem
+ elif the filesystem is mounting or unmounting then
+ this_error = -1
+ elif the fileserver is down then
+ this_error = -1
+ elif the filesystem is already mounted
+ this_error = 0
+ break
+ fi
+ if no error on this mount then
+ this_error = initialise mount point
+ fi
+ if no error on this mount and mount is delayed then
+ this_error = -1
+ fi
+ if this_error < 0 then
+ retry = true
+ fi
+ if no error on this mount then
+ make mount point if required
+ fi
+ if no error on this mount then
+ if mount in background then
+ run mount in background
+ return -1
+ else
+ this_error = mount in foreground
+ fi
+ fi
+ if an error occured on this mount then
+ update stats
+ save error in mount point
+ fi
+endfor
+ */
+
+static int afs_bgmount P((struct continuation *cp, int mpe));
+static int afs_bgmount(cp, mpe)
+struct continuation *cp;
+int mpe;
+{
+ mntfs *mf = cp->mp->am_mnt; /* Current mntfs */
+ mntfs *mf_retry = 0; /* First mntfs which needed retrying */
+ int this_error = -1; /* Per-mount error */
+ int hard_error = -1;
+ int mp_error = mpe;
+
+ /*
+ * Try to mount each location.
+ * At the end:
+ * hard_error == 0 indicates something was mounted.
+ * hard_error > 0 indicates everything failed with a hard error
+ * hard_error < 0 indicates nothing could be mounted now
+ */
+ for (; this_error && *cp->ivec; cp->ivec++) {
+ am_ops *p;
+ am_node *mp = cp->mp;
+ char *link_dir;
+ int dont_retry;
+
+ if (hard_error < 0)
+ hard_error = this_error;
+
+ this_error = -1;
+
+ if (**cp->ivec == '-') {
+ /*
+ * Pick up new defaults
+ */
+ if (cp->auto_opts && *cp->auto_opts)
+ cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec+1);
+ else
+ cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
+#ifdef DEBUG
+ dlog("Setting def_opts to \"%s\"", cp->def_opts);
+#endif /* DEBUG */
+ continue;
+ }
+
+ /*
+ * If a mount has been attempted, and we find
+ * a cut then don't try any more locations.
+ */
+ if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
+ if (cp->tried) {
+#ifdef DEBUG
+ dlog("Cut: not trying any more locations for %s",
+ mp->am_path);
+#endif /* DEBUG */
+ break;
+ }
+ continue;
+ }
+
+#ifdef SUNOS4_COMPAT
+#ifdef nomore
+ /*
+ * By default, you only get this bit on SunOS4.
+ * If you want this anyway, then define SUNOS4_COMPAT
+ * in the relevant "os-blah.h" file.
+ *
+ * We make the observation that if the local key line contains
+ * no '=' signs then either it is sick, or it is a SunOS4-style
+ * "host:fs[:link]" line. In the latter case the am_opts field
+ * is also assumed to be in old-style, so you can't mix & match.
+ * You can use ${} expansions for the fs and link bits though...
+ *
+ * Actually, this doesn't really cover all the possibilities for
+ * the latest SunOS automounter and it is debatable whether there
+ * is any point bothering.
+ */
+ if (strchr(*cp->ivec, '=') == 0)
+ p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
+ else
+#endif
+#endif /* SUNOS4_COMPAT */
+ p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
+
+ /*
+ * Find a mounted filesystem for this node.
+ */
+ mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
+ cp->fs_opts.fs_mtab, cp->auto_opts, cp->fs_opts.opt_opts, cp->fs_opts.opt_remopts);
+
+ p = mf->mf_ops;
+#ifdef DEBUG
+ dlog("Got a hit with %s", p->fs_type);
+#endif /* DEBUG */
+ /*
+ * Note whether this is a real mount attempt
+ */
+ if (p == &efs_ops) {
+ plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
+ if (this_error <= 0)
+ this_error = ENOENT;
+ continue;
+ } else {
+ if (cp->fs_opts.fs_mtab) {
+ plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
+ cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
+ }
+ cp->tried = TRUE;
+ }
+
+ this_error = 0;
+ dont_retry = FALSE;
+
+ if (mp->am_link) {
+ free(mp->am_link);
+ mp->am_link = 0;
+ }
+
+ link_dir = mf->mf_fo->opt_sublink;
+
+ if (link_dir && *link_dir) {
+ if (*link_dir == '/') {
+ mp->am_link = strdup(link_dir);
+ } else {
+ mp->am_link = str3cat((char *) 0,
+ mf->mf_fo->opt_fs, "/", link_dir);
+ normalize_slash(mp->am_link);
+ }
+ }
+
+ if (mf->mf_error > 0) {
+ this_error = mf->mf_error;
+ } else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
+ /*
+ * Still mounting - retry later
+ */
+#ifdef DEBUG
+ dlog("Duplicate pending mount fstype %s", p->fs_type);
+#endif /* DEBUG */
+ this_error = -1;
+ } else if (FSRV_ISDOWN(mf->mf_server)) {
+ /*
+ * Would just mount from the same place
+ * as a hung mount - so give up
+ */
+#ifdef DEBUG
+ dlog("%s is already hung - giving up", mf->mf_mount);
+#endif /* DEBUG */
+ mp_error = EWOULDBLOCK;
+ dont_retry = TRUE;
+ this_error = -1;
+ } else if (mf->mf_flags & MFF_MOUNTED) {
+#ifdef DEBUG
+ dlog("duplicate mount of \"%s\" ...", mf->mf_info);
+#endif /* DEBUG */
+ /*
+ * Just call mounted()
+ */
+ am_mounted(mp);
+
+ this_error = 0;
+ break;
+ }
+
+ /*
+ * Will usually need to play around with the mount nodes
+ * file attribute structure. This must be done here.
+ * Try and get things initialised, even if the fileserver
+ * is not known to be up. In the common case this will
+ * progress things faster.
+ */
+ if (!this_error) {
+ /*
+ * Fill in attribute fields.
+ */
+ if (mf->mf_ops->fs_flags & FS_DIRECTORY)
+ mk_fattr(mp, NFDIR);
+ else
+ mk_fattr(mp, NFLNK);
+
+ mp->am_fattr.fileid = mp->am_gen;
+
+ if (p->fs_init)
+ this_error = (*p->fs_init)(mf);
+ }
+
+ /*
+ * Make sure the fileserver is UP before doing any more work
+ */
+ if (!FSRV_ISUP(mf->mf_server)) {
+#ifdef DEBUG
+ dlog("waiting for server %s to become available", mf->mf_server->fs_host);
+#endif
+ this_error = -1;
+ }
+
+ if (!this_error && mf->mf_fo->opt_delay) {
+ /*
+ * If there is a delay timer on the mount
+ * then don't try to mount if the timer
+ * has not expired.
+ */
+ int i = atoi(mf->mf_fo->opt_delay);
+ if (i > 0 && clocktime() < (cp->start + i)) {
+#ifdef DEBUG
+ dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start);
+#endif /* DEBUG */
+ this_error = -1;
+ }
+ }
+
+ if (this_error < 0 && !dont_retry) {
+ if (!mf_retry)
+ mf_retry = dup_mntfs(mf);
+ cp->retry = TRUE;
+ }
+
+ if (!this_error)
+ if (p->fs_flags & FS_MBACKGROUND) {
+ mf->mf_flags |= MFF_MOUNTING; /*XXX*/
+#ifdef DEBUG
+ dlog("backgrounding mount of \"%s\"", mf->mf_mount);
+#endif /* DEBUG */
+ if (cp->callout) {
+ untimeout(cp->callout);
+ cp->callout = 0;
+ }
+ run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
+ mf->mf_flags |= MFF_MKMNT; /* XXX */
+ if (mf_retry) free_mntfs(mf_retry);
+ return -1;
+ } else {
+#ifdef DEBUG
+ dlog("foreground mount of \"%s\" ...", mf->mf_info);
+#endif /* DEBUG */
+ this_error = try_mount((voidp) mp);
+ if (this_error < 0) {
+ if (!mf_retry)
+ mf_retry = dup_mntfs(mf);
+ cp->retry = TRUE;
+ }
+ }
+
+ if (this_error >= 0) {
+ if (this_error > 0) {
+ amd_stats.d_merr++;
+ if (mf != mf_retry) {
+ mf->mf_error = this_error;
+ mf->mf_flags |= MFF_ERROR;
+ }
+ }
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+ }
+ }
+
+ if (this_error && cp->retry) {
+ free_mntfs(mf);
+ mf = cp->mp->am_mnt = mf_retry;
+ /*
+ * Not retrying again (so far)
+ */
+ cp->retry = FALSE;
+ cp->tried = FALSE;
+ /*
+ * Start at the beginning.
+ * Rewind the location vector and
+ * reset the default options.
+ */
+ cp->ivec = cp->xivec;
+ cp->def_opts = strealloc(cp->def_opts, cp->auto_opts);
+ /*
+ * Arrange that afs_bgmount is called
+ * after anything else happens.
+ */
+#ifdef DEBUG
+ dlog("Arranging to retry mount of %s", cp->mp->am_path);
+#endif /* DEBUG */
+ sched_task(afs_retry, (voidp) cp, (voidp) mf);
+ if (cp->callout)
+ untimeout(cp->callout);
+ cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
+
+ cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
+
+ /*
+ * Not done yet - so don't return anything
+ */
+ return -1;
+ }
+
+ if (hard_error < 0 || this_error == 0)
+ hard_error = this_error;
+
+ /*
+ * Discard handle on duff filesystem.
+ * This should never happen since it
+ * should be caught by the case above.
+ */
+ if (mf_retry) {
+ if (hard_error)
+ plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
+ free_mntfs(mf_retry);
+ }
+
+ /*
+ * If we get here, then either the mount succeeded or
+ * there is no more mount information available.
+ */
+ if (hard_error < 0 && mp_error)
+ hard_error = cp->mp->am_error = mp_error;
+ if (hard_error > 0) {
+ /*
+ * Set a small(ish) timeout on an error node if
+ * the error was not a time out.
+ */
+ switch (hard_error) {
+ case ETIMEDOUT:
+ case EWOULDBLOCK:
+ cp->mp->am_timeo = 5;
+ break;
+ default:
+ cp->mp->am_timeo = 17;
+ break;
+ }
+ new_ttl(cp->mp);
+ }
+
+ /*
+ * Make sure that the error value in the mntfs has a
+ * reasonable value.
+ */
+ if (mf->mf_error < 0) {
+ mf->mf_error = hard_error;
+ if (hard_error)
+ mf->mf_flags |= MFF_ERROR;
+ }
+
+ /*
+ * In any case we don't need the continuation any more
+ */
+ free_continuation(cp);
+
+ return hard_error;
+}
+
+/*
+ * Automount interface to RPC lookup routine
+ */
+static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op));
+static am_node *afs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+#define ereturn(x) { *error_return = x; return 0; }
+
+ /*
+ * Find the corresponding entry and return
+ * the file handle for it.
+ */
+ am_node *ap, *new_mp, *ap_hung;
+ char *info; /* Mount info - where to get the file system */
+ char **ivec, **xivec; /* Split version of info */
+ char *auto_opts; /* Automount options */
+ int error = 0; /* Error so far */
+ char path_name[MAXPATHLEN]; /* General path name buffer */
+ char *pfname; /* Path for database lookup */
+ struct continuation *cp; /* Continuation structure if we need to mount */
+ int in_progress = 0; /* # of (un)mount in progress */
+ char *dflts;
+ mntfs *mf;
+
+#ifdef DEBUG
+ dlog("in afs_lookuppn");
+#endif /* DEBUG */
+
+ /*
+ * If the server is shutting down
+ * then don't return information
+ * about the mount point.
+ */
+ if (amd_state == Finishing) {
+#ifdef DEBUG
+ if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_ops)
+ dlog("%s mount ignored - going down", fname);
+ else
+ dlog("%s/%s mount ignored - going down", mp->am_path, fname);
+#endif /* DEBUG */
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Handle special case of "." and ".."
+ */
+ if (fname[0] == '.') {
+ if (fname[1] == '\0')
+ return mp; /* "." is the current node */
+ if (fname[1] == '.' && fname[2] == '\0') {
+ if (mp->am_parent) {
+#ifdef DEBUG
+ dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
+#endif /* DEBUG */
+ return mp->am_parent; /* ".." is the parent node */
+ }
+ ereturn(ESTALE);
+ }
+ }
+
+ /*
+ * Check for valid key name.
+ * If it is invalid then pretend it doesn't exist.
+ */
+ if (!valid_key(fname)) {
+ plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
+ ereturn(ENOENT);
+ }
+
+ /*
+ * Expand key name.
+ * fname is now a private copy.
+ */
+ fname = expand_key(fname);
+
+ for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
+ /*
+ * Otherwise search children of this node
+ */
+ if (FSTREQ(ap->am_name, fname)) {
+ mf = ap->am_mnt;
+ if (ap->am_error) {
+ error = ap->am_error;
+ continue;
+ }
+
+ /*
+ * If the error code is undefined then it must be
+ * in progress.
+ */
+ if (mf->mf_error < 0)
+ goto in_progrss;
+
+ /*
+ * Check for a hung node
+ */
+ if (FSRV_ISDOWN(mf->mf_server)) {
+#ifdef DEBUG
+ dlog("server hung");
+#endif /* DEBUG */
+ error = ap->am_error;
+ ap_hung = ap;
+ continue;
+ }
+
+ /*
+ * If there was a previous error with this node
+ * then return that error code.
+ */
+ if (mf->mf_flags & MFF_ERROR) {
+ error = mf->mf_error;
+ continue;
+ }
+
+ if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
+in_progrss:
+ /*
+ * If the fs is not mounted or it is unmounting then there
+ * is a background (un)mount in progress. In this case
+ * we just drop the RPC request (return nil) and
+ * wait for a retry, by which time the (un)mount may
+ * have completed.
+ */
+#ifdef DEBUG
+ dlog("ignoring mount of %s in %s -- in progress",
+ fname, mf->mf_mount);
+#endif /* DEBUG */
+ in_progress++;
+ continue;
+ }
+
+ /*
+ * Otherwise we have a hit: return the current mount point.
+ */
+#ifdef DEBUG
+ dlog("matched %s in %s", fname, ap->am_path);
+#endif /* DEBUG */
+ free(fname);
+ return ap;
+ }
+ }
+
+ if (in_progress) {
+#ifdef DEBUG
+ dlog("Waiting while %d mount(s) in progress", in_progress);
+#endif /* DEBUG */
+ free(fname);
+ ereturn(-1);
+ }
+
+ /*
+ * If an error occured then return it.
+ */
+ if (error) {
+#ifdef DEBUG
+ errno = error; /* XXX */
+ dlog("Returning error: %m", error);
+#endif /* DEBUG */
+ free(fname);
+ ereturn(error);
+ }
+
+ /*
+ * If doing a delete then don't create again!
+ */
+ switch (op) {
+ case VLOOK_DELETE:
+ ereturn(ENOENT);
+ break;
+
+ case VLOOK_CREATE:
+ break;
+
+ default:
+ plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
+ ereturn(EINVAL);
+ break;
+ }
+
+ /*
+ * If the server is going down then just return,
+ * don't try to mount any more file systems
+ */
+ if ((int)amd_state >= (int)Finishing) {
+#ifdef DEBUG
+ dlog("not found - server going down anyway");
+#endif /* DEBUG */
+ free(fname);
+ ereturn(ENOENT);
+ }
+
+ /*
+ * If we get there then this is a reference to an,
+ * as yet, unknown name so we need to search the mount
+ * map for it.
+ */
+ if (mp->am_pref) {
+ sprintf(path_name, "%s%s", mp->am_pref, fname);
+ pfname = path_name;
+ } else {
+ pfname = fname;
+ }
+
+ mf = mp->am_mnt;
+
+#ifdef DEBUG
+ dlog("will search map info in %s to find %s", mf->mf_info, pfname);
+#endif /* DEBUG */
+ /*
+ * Consult the oracle for some mount information.
+ * info is malloc'ed and belongs to this routine.
+ * It ends up being free'd in free_continuation().
+ *
+ * Note that this may return -1 indicating that information
+ * is not yet available.
+ */
+ error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
+ if (error) {
+ if (error > 0)
+ plog(XLOG_MAP, "No map entry for %s", pfname);
+ else
+ plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
+ free(fname);
+ ereturn(error);
+ }
+
+#ifdef DEBUG
+ dlog("mount info is %s", info);
+#endif /* DEBUG */
+
+ /*
+ * Split info into an argument vector.
+ * The vector is malloc'ed and belongs to
+ * this routine. It is free'd in free_continuation()
+ */
+ xivec = ivec = strsplit(info, ' ', '\"');
+
+ /*
+ * Default error code...
+ */
+ if (ap_hung)
+ error = EWOULDBLOCK;
+ else
+ error = ENOENT;
+
+ /*
+ * Allocate a new map
+ */
+ new_mp = exported_ap_alloc();
+ if (new_mp == 0) {
+ free((voidp) xivec);
+ free((voidp) info);
+ free((voidp) fname);
+ ereturn(ENOSPC);
+ }
+
+ if (mf->mf_auto)
+ auto_opts = mf->mf_auto;
+ else
+ auto_opts = "";
+
+ auto_opts = strdup(auto_opts);
+
+#ifdef DEBUG
+ dlog("searching for /defaults entry");
+#endif /* DEBUG */
+ if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
+ char *dfl;
+ char **rvec;
+#ifdef DEBUG
+ dlog("/defaults gave %s", dflts);
+#endif /* DEBUG */
+ if (*dflts == '-')
+ dfl = dflts+1;
+ else
+ dfl = dflts;
+
+ /*
+ * Chop the defaults up
+ */
+ rvec = strsplit(dfl, ' ', '\"');
+ /*
+ * Extract first value
+ */
+ dfl = rvec[0];
+
+ /*
+ * If there were any values at all...
+ */
+ if (dfl) {
+ /*
+ * Log error if there were other values
+ */
+ if (rvec[1]) {
+#ifdef DEBUG
+ dlog("/defaults chopped into %s", dfl);
+#endif /* DEBUG */
+ plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
+ }
+
+ /*
+ * Prepend to existing defaults if they exist,
+ * otherwise just use these defaults.
+ */
+ if (*auto_opts && *dfl) {
+ char *nopts = (char *) xmalloc(strlen(auto_opts)+strlen(dfl)+2);
+ sprintf(nopts, "%s;%s", dfl, auto_opts);
+ free(auto_opts);
+ auto_opts = nopts;
+ } else if (*dfl) {
+ auto_opts = strealloc(auto_opts, dfl);
+ }
+ }
+ free(dflts);
+ /*
+ * Don't need info vector any more
+ */
+ free((voidp) rvec);
+ }
+
+ /*
+ * Fill it in
+ */
+ init_map(new_mp, fname);
+
+ /*
+ * Put it in the table
+ */
+ insert_am(new_mp, mp);
+
+ /*
+ * Fill in some other fields,
+ * path and mount point.
+ *
+ * bugfix: do not prepend old am_path if direct map
+ * <wls@astro.umd.edu> William Sebok
+ */
+ new_mp->am_path = str3cat(new_mp->am_path,
+ mf->mf_ops == &dfs_ops ? "" : mp->am_path,
+ *fname == '/' ? "" : "/", fname);
+
+#ifdef DEBUG
+ dlog("setting path to %s", new_mp->am_path);
+#endif /* DEBUG */
+
+ /*
+ * Take private copy of pfname
+ */
+ pfname = strdup(pfname);
+
+ /*
+ * Construct a continuation
+ */
+ cp = ALLOC(continuation);
+ cp->mp = new_mp;
+ cp->xivec = xivec;
+ cp->ivec = ivec;
+ cp->info = info;
+ cp->key = pfname;
+ cp->auto_opts = auto_opts;
+ cp->retry = FALSE;
+ cp->tried = FALSE;
+ cp->start = clocktime();
+ cp->def_opts = strdup(auto_opts);
+ bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
+
+ /*
+ * Try and mount the file system
+ * If this succeeds immediately (possible
+ * for a ufs file system) then return
+ * the attributes, otherwise just
+ * return an error.
+ */
+ error = afs_bgmount(cp, error);
+ reschedule_timeout_mp();
+ if (!error) {
+ free(fname);
+ return new_mp;
+ }
+
+ if (error && (cp->mp->am_mnt->mf_ops == &efs_ops))
+ cp->mp->am_error = error;
+
+ assign_error_mntfs(new_mp);
+
+ free(fname);
+
+ ereturn(error);
+#undef ereturn
+}
+
+/*
+ * Locate next node in sibling list which is mounted
+ * and is not an error node.
+ */
+static am_node *next_nonerror_node P((am_node *xp));
+static am_node *next_nonerror_node(xp)
+am_node *xp;
+{
+ mntfs *mf;
+
+ /*
+ * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
+ * Fixes a race condition when mounting direct automounts.
+ * Also fixes a problem when doing a readdir on a directory
+ * containing hung automounts.
+ */
+ while (xp &&
+ (!(mf = xp->am_mnt) || /* No mounted filesystem */
+ mf->mf_error != 0 || /* There was a mntfs error */
+ xp->am_error != 0 || /* There was a mount error */
+ !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
+ (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
+ )
+ xp = xp->am_osib;
+
+ return xp;
+}
+
+static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count));
+static int afs_readdir(mp, cookie, dp, ep, count)
+am_node *mp;
+nfscookie cookie;
+struct dirlist *dp;
+struct entry *ep;
+int count;
+{
+ unsigned int gen = *(unsigned int*) cookie;
+ am_node *xp;
+
+ dp->eof = FALSE;
+
+ if (gen == 0) {
+ /*
+ * In the default instance (which is used to
+ * start a search) we return "." and "..".
+ *
+ * This assumes that the count is big enough
+ * to allow both "." and ".." to be returned in
+ * a single packet. If it isn't (which would
+ * be fairly unbelievable) then tough.
+ */
+#ifdef DEBUG
+ dlog("default search");
+#endif /* DEBUG */
+ /*
+ * Check for enough room. This is extremely
+ * approximate but is more than enough space.
+ * Really need 2 times:
+ * 4byte fileid
+ * 4byte cookie
+ * 4byte name length
+ * 4byte name
+ * plus the dirlist structure
+ */
+ if (count <
+ (2 * (2 * (sizeof(*ep) + sizeof("..") + 4)
+ + sizeof(*dp))))
+ return EINVAL;
+
+ xp = next_nonerror_node(mp->am_child);
+ dp->entries = ep;
+
+ /* construct "." */
+ ep[0].fileid = mp->am_gen;
+ ep[0].name = ".";
+ ep[0].nextentry = &ep[1];
+ *(unsigned int *) ep[0].cookie = 0;
+
+ /* construct ".." */
+ if (mp->am_parent)
+ ep[1].fileid = mp->am_parent->am_gen;
+ else
+ ep[1].fileid = mp->am_gen;
+ ep[1].name = "..";
+ ep[1].nextentry = 0;
+ *(unsigned int *) ep[1].cookie =
+ xp ? xp->am_gen : ~(unsigned int)0;
+
+ if (!xp) dp->eof = TRUE;
+ return 0;
+ }
+
+#ifdef DEBUG
+ dlog("real child");
+#endif /* DEBUG */
+
+ if (gen == ~(unsigned int)0) {
+#ifdef DEBUG
+ dlog("End of readdir in %s", mp->am_path);
+#endif /* DEBUG */
+ dp->eof = TRUE;
+ dp->entries = 0;
+ return 0;
+ }
+
+ xp = mp->am_child;
+ while (xp && xp->am_gen != gen)
+ xp = xp->am_osib;
+
+ if (xp) {
+ int nbytes = count / 2; /* conservative */
+ int todo = MAX_READDIR_ENTRIES;
+ dp->entries = ep;
+ do {
+ am_node *xp_next = next_nonerror_node(xp->am_osib);
+
+ if (xp_next) {
+ *(unsigned int *) ep->cookie = xp_next->am_gen;
+ } else {
+ *(unsigned int *) ep->cookie = ~(unsigned int)0;
+ dp->eof = TRUE;
+ }
+
+ ep->fileid = xp->am_gen;
+ ep->name = xp->am_name;
+ nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1;
+
+ xp = xp_next;
+
+ if (nbytes > 0 && !dp->eof && todo > 1) {
+ ep->nextentry = ep + 1;
+ ep++;
+ --todo;
+ } else {
+ todo = 0;
+ }
+ } while (todo > 0);
+
+ ep->nextentry = 0;
+
+ return 0;
+ }
+
+ return ESTALE;
+
+}
+
+static am_node *dfs_readlink P((am_node *mp, int *error_return));
+static am_node *dfs_readlink(mp, error_return)
+am_node *mp;
+int *error_return;
+{
+ am_node *xp;
+ int rc = 0;
+
+ xp = next_nonerror_node(mp->am_child);
+ if (!xp) {
+ if (!mp->am_mnt->mf_private)
+ afs_mkcacheref(mp->am_mnt); /* XXX */
+ xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
+ }
+
+ if (xp) {
+ new_ttl(xp); /* (7/12/89) from Rein Tollevik */
+ return xp;
+ }
+ if (amd_state == Finishing)
+ rc = ENOENT;
+ *error_return = rc;
+ return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops root_ops = {
+ "root",
+ 0, /* root_match */
+ 0, /* root_init */
+ root_mount,
+ 0,
+ afs_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* root_readlink */
+ 0, /* root_mounted */
+ 0, /* root_umounted */
+ find_afs_srvr,
+ FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops afs_ops = {
+ "auto",
+ afs_match,
+ 0, /* afs_init */
+ afs_mount,
+ 0,
+ afs_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* afs_readlink */
+ 0, /* afs_mounted */
+ afs_umounted,
+ find_afs_srvr,
+ FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops toplvl_ops = {
+ "toplvl",
+ afs_match,
+ 0, /* afs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* toplvl_readlink */
+ toplvl_mounted,
+ 0, /* toplvl_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
+};
+
+am_ops dfs_ops = {
+ "direct",
+ afs_match,
+ 0, /* dfs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ efs_lookuppn,
+ efs_readdir,
+ dfs_readlink,
+ toplvl_mounted,
+ 0, /* afs_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#ifdef HAS_UNION_FS
+am_ops union_ops = {
+ "union",
+ afs_match,
+ 0, /* afs_init */
+ toplvl_mount,
+ 0,
+ toplvl_umount,
+ 0,
+ afs_lookuppn,
+ afs_readdir,
+ 0, /* toplvl_readlink */
+ union_mounted,
+ 0, /* toplvl_umounted */
+ find_afs_srvr,
+ FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
+};
+#endif /* HAS_UNION_FS */
diff --git a/usr.sbin/amd/amd/am_ops.c b/usr.sbin/amd/amd/am_ops.c
new file mode 100644
index 0000000..4360110
--- /dev/null
+++ b/usr.sbin/amd/amd/am_ops.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)am_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: am_ops.c,v 5.2.2.1 1992/02/09 15:08:17 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+static am_ops *vops[] = {
+#ifdef HAS_UFS
+ &ufs_ops,
+#endif
+#ifdef HAS_NFS
+ &nfs_ops,
+#endif
+#ifdef HAS_NFSX
+ &nfsx_ops,
+#endif
+#ifdef HAS_HOST
+ &host_ops,
+#endif
+#ifdef HAS_SFS
+ &sfs_ops,
+#endif
+#ifdef HAS_SFSX
+ &sfsx_ops,
+#endif
+#ifdef HAS_LOFS
+ &lofs_ops,
+#endif
+#ifdef HAS_PFS
+ &pfs_ops,
+#endif
+#ifdef HAS_UNION_FS
+ &union_ops,
+#endif
+ &afs_ops, /* These four should be last ... */
+ &dfs_ops, /* ... */
+ &toplvl_ops, /* ... */
+ &efs_ops, /* ... in the order afs; dfs; toplvl; efs */
+ 0
+};
+
+void ops_showfstypes P((FILE *fp));
+void ops_showfstypes(fp)
+FILE *fp;
+{
+ struct am_ops **ap;
+ int l = 0;
+
+ for (ap = vops; *ap; ap++) {
+ fputs((*ap)->fs_type, fp);
+ if (ap[1]) fputs(", ", fp);
+ l += strlen((*ap)->fs_type) + 2;
+ if (l > 60) { l = 0; fputs("\n ", fp); }
+ }
+}
+
+#ifdef SUNOS4_COMPAT
+#ifdef nomore
+/*
+ * Crack a SunOS4-style host:fs:sub-link line
+ * Construct an amd-style line and call the
+ * normal amd matcher.
+ */
+am_ops *sunos4_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+ char *host = key;
+ char *fs = strchr(host, ':');
+ char *sublink = fs ? strchr(fs+1, ':') : 0;
+ char keybuf[MAXPATHLEN];
+
+ sprintf(keybuf, "type:=nfs;rhost:=%s;rfs:=%s;sublink:=%s;opts:=%s", host,
+ fs ? fs+1 : "",
+ sublink ? sublink+1 : "",
+ g_key);
+ return ops_match(fo, keybuf, "", path, keym, map);
+}
+#endif
+#endif /* SUNOS4_COMPAT */
+
+am_ops *ops_match(fo, key, g_key, path, keym, map)
+am_opts *fo;
+char *key;
+char *g_key;
+char *path;
+char *keym;
+char *map;
+{
+ am_ops **vp;
+ am_ops *rop = 0;
+
+ /*
+ * First crack the global opts and the local opts
+ */
+ if (!eval_fs_opts(fo, key, g_key, path, keym, map)) {
+ rop = &efs_ops;
+ } else if (fo->opt_type == 0) {
+ plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map);
+ rop = &efs_ops;
+ } else {
+ /*
+ * Next find the correct filesystem type
+ */
+ for (vp = vops; rop = *vp; vp++)
+ if (strcmp(rop->fs_type, fo->opt_type) == 0)
+ break;
+
+ if (!rop) {
+ plog(XLOG_USER, "fs type \"%s\" not recognised", fo->opt_type);
+ rop = &efs_ops;
+ }
+ }
+
+ /*
+ * Make sure we have a default mount option.
+ * Otherwise skip past any leading '-'.
+ */
+ if (fo->opt_opts == 0)
+ fo->opt_opts = "rw,defaults";
+ else if (*fo->opt_opts == '-')
+ fo->opt_opts++;
+
+ /*
+ * Check the filesystem is happy
+ */
+ if (fo->fs_mtab)
+ free((voidp) fo->fs_mtab);
+
+ if (fo->fs_mtab = (*rop->fs_match)(fo))
+ return rop;
+
+ /*
+ * Return error file system
+ */
+ fo->fs_mtab = (*efs_ops.fs_match)(fo);
+ return &efs_ops;
+}
diff --git a/usr.sbin/amd/amd/amd.8 b/usr.sbin/amd/amd/amd.8
new file mode 100644
index 0000000..9fa01a2
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.8
@@ -0,0 +1,232 @@
+.\"
+.\" Copyright (c) 1989 Jan-Simon Pendry
+.\" Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+.\" Copyright (c) 1989, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Jan-Simon Pendry at Imperial College, London.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)amd.8 5.10 (Berkeley) 4/19/94
+.\"
+.\" $Id: amd.8,v 5.2.2.1 1992/02/09 15:11:39 jsp beta $
+.\"
+.Dd "April 19, 1994"
+.Dt AMD 8
+.Os
+.Sh NAME
+.Nm amd
+.Nd automatically mount file systems
+.Sh SYNOPSIS
+.Nm amd
+.Op Fl nprv
+.Op Fl a Ar mount_point
+.Op Fl c Ar duration
+.Op Fl d Ar domain
+.Bk -words
+.Op Fl k Ar kernel-arch
+.Ek
+.Op Fl l Ar logfile
+.Op Fl t Ar interval.interval
+.Bk -words
+.Op Fl w Ar interval
+.Ek
+.Op Fl x Ar log-option
+.Op Fl y Ar YP-domain
+.Bk -words
+.Op Fl C Ar cluster-name
+.Ek
+.Op Fl D Ar option
+.Oo
+.Ar directory mapname
+.Op Fl map-options
+.Oc
+.Ar ...
+.Sh DESCRIPTION
+.Nm Amd
+is a daemon that automatically mounts filesystems
+whenever a file or directory
+within that filesystem is accessed.
+Filesystems are automatically unmounted when they
+appear to be quiescent.
+.Pp
+.Nm Amd
+operates by attaching itself as an
+.Tn NFS
+server to each of the specified
+.Ar directories .
+Lookups within the specified directories
+are handled by
+.Nm amd ,
+which uses the map defined by
+.Ar mapname
+to determine how to resolve the lookup.
+Generally, this will be a host name, some filesystem information
+and some mount options for the given filesystem.
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl a Ar temporary-directory
+Specify an alternative location for the real mount points.
+The default is
+.Pa /a .
+.It Fl c Ar duration
+Specify a
+.Ar duration ,
+in seconds, that a looked up name remains
+cached when not in use. The default is 5 minutes.
+.It Fl d Ar domain
+Specify the local domain name. If this option is not
+given the domain name is determined from the hostname.
+.It Fl k Ar kernel-arch
+Specifies the kernel architecture. This is used solely
+to set the ${karch} selector.
+.It Fl l Ar logfile
+Specify a logfile in which to record mount and unmount events.
+If
+.Ar logfile
+is the string
+.Em syslog ,
+the log messages will be sent to the system log daemon by
+.Xr syslog 3 .
+.It Fl n
+Normalize hostnames.
+The name referred to by ${rhost} is normalized relative to the
+host database before being used. The effect is to translate
+aliases into ``official'' names.
+.It Fl p
+Print
+.Em PID .
+Outputs the process-id of
+.Nm amd
+to standard output where it can be saved into a file.
+.It Fl r
+Restart existing mounts.
+.Nm Amd
+will scan the mount file table to determine which filesystems
+are currently mounted. Whenever one of these would have
+been auto-mounted,
+.Nm amd
+.Em inherits
+it.
+.It Fl t Ar interval.interval
+Specify the
+.Ar interval ,
+in tenths of a second, between
+.Tn NFS/RPC/UDP
+retries.
+The default is 0.8 seconds.
+The second values alters the retransmit counter.
+Useful defaults are supplied if either or both
+values are missing.
+.It Fl v
+Version. Displays version and configuration information on standard error.
+.It Fl w Ar interval
+Specify an
+.Ar interval ,
+in seconds, between attempts to dismount
+filesystems that have exceeded their cached times.
+The default is 2 minutes.
+.It Fl y Ar domain
+Specify an alternative
+.Tn NIS
+domain from which to fetch the
+.Tn NIS
+maps.
+The default is the system domain name.
+This option is ignored if
+.Tn NIS
+support is not available.
+.It Fl x Ar options
+Specify run-time logging options. The options are a comma separated
+list chosen from: fatal, error, user, warn, info, map, stats, all.
+.It Fl D Ar option
+Select from a variety of debug options. Prefixing an
+option with the string
+.Em no
+reverses the effect of that option. Options are cumulative.
+The most useful option is
+.Ar all .
+.El
+.Pp
+Since
+.Fl D
+is only used for debugging other options are not documented here:
+the current supported set of options is listed by the
+.Fl v
+option
+and a fuller description is available in the program source.
+.Sh FILES
+.Bl -tag -width /axx
+.It Pa /a
+directory under which filesystems are dynamically mounted
+.El
+.Sh CAVEATS
+Some care may be required when creating a mount map.
+.Pp
+Symbolic links on an
+.Tn NFS
+filesystem can be incredibly inefficient.
+In most implementations of
+.Tn NFS ,
+their interpolations are not cached by
+the kernel and each time a symbolic link is
+encountered during a
+.Em lookuppn
+translation it costs an
+.Tn RPC
+call to the
+.Tn NFS
+server.
+A large improvement in real-time
+performance could be gained by adding a cache somewhere.
+Replacing
+.Xr symlinks 2
+with a suitable incarnation of the auto-mounter
+results in a large real-time speedup, but also causes a large
+number of process context switches.
+.Pp
+A weird imagination is most useful to gain full advantage of all
+the features.
+.Sh SEE ALSO
+.Xr amq 8 ,
+.Xr hostname 1 ,
+.Xr mount 8 ,
+.Xr umount 8 ,
+.Rs
+.%T Amd \- The 4.4 BSD Automounter
+.Re
+.Sh AUTHOR
+.An Jan-Simon Pendry
+<jsp@doc.ic.ac.uk>, Department of Computing, Imperial College, London, UK.
+.Sh HISTORY
+The
+.Nm amd
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/amd/amd/amd.c b/usr.sbin/amd/amd/amd.c
new file mode 100644
index 0000000..c3b2b61
--- /dev/null
+++ b/usr.sbin/amd/amd/amd.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amd.c,v 5.2.2.1 1992/02/09 15:08:15 jsp beta $
+ *
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Automounter
+ */
+
+#include "am.h"
+#include <sys/signal.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+char pid_fsname[16 + MAXHOSTNAMELEN]; /* "kiska.southseas.nz:(pid%d)" */
+char *progname; /* "amd" */
+#ifdef HAS_HOST
+#ifdef HOST_EXEC
+char *host_helper;
+#endif /* HOST_EXEC */
+#endif /* HAS_HOST */
+char *auto_dir = "/a";
+char *hostdomain = "unknown.domain";
+char hostname[MAXHOSTNAMELEN] = "localhost"; /* Hostname */
+char hostd[2*MAXHOSTNAMELEN]; /* Host+domain */
+char *op_sys = OS_REP; /* Name of current op_sys */
+char *arch = ARCH_REP; /* Name of current architecture */
+char *endian = ARCH_ENDIAN; /* Big or Little endian */
+char *wire;
+int foreground = 1; /* This is the top-level server */
+int mypid; /* Current process id */
+int immediate_abort; /* Should close-down unmounts be retried */
+struct in_addr myipaddr; /* (An) IP address of this host */
+serv_state amd_state;
+struct amd_stats amd_stats; /* Server statistics */
+time_t do_mapc_reload = 0; /* mapc_reload() call required? */
+jmp_buf select_intr;
+int select_intr_valid;
+int orig_umask;
+
+/*
+ * Signal handler:
+ * SIGINT - tells amd to do a full shutdown, including unmounting all filesystem.
+ * SIGTERM - tells amd to shutdown now. Just unmounts the automount nodes.
+ */
+static void sigterm(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+ signal(sig, sigterm);
+#endif /* SYS5_SIGNALS */
+
+ switch (sig) {
+ case SIGINT:
+ immediate_abort = 15;
+ break;
+
+ case SIGTERM:
+ immediate_abort = -1;
+ /* fall through... */
+
+ default:
+ plog(XLOG_WARNING, "WARNING: automounter going down on signal %d", sig);
+ break;
+ }
+ if (select_intr_valid)
+ longjmp(select_intr, sig);
+}
+
+/*
+ * Hook for cache reload.
+ * When a SIGHUP arrives it schedules a call to mapc_reload
+ */
+/*ARGSUSED*/
+static void sighup(sig)
+int sig;
+{
+#ifdef SYS5_SIGNALS
+ signal(sig, sighup);
+#endif /* SYS5_SIGNALS */
+
+#ifdef DEBUG
+ if (sig != SIGHUP)
+ dlog("spurious call to sighup");
+#endif /* DEBUG */
+ /*
+ * Force a reload by zero'ing the timer
+ */
+ if (amd_state == Run)
+ do_mapc_reload = 0;
+}
+
+/*ARGSUSED*/
+static void parent_exit(sig)
+int sig;
+{
+ exit(0);
+}
+
+static int daemon_mode(P_void)
+{
+ int bgpid;
+
+ signal(SIGQUIT, parent_exit);
+ bgpid = background();
+
+ if (bgpid != 0) {
+ if (print_pid) {
+ printf("%d\n", bgpid);
+ fflush(stdout);
+ }
+ /*
+ * Now wait for the automount points to
+ * complete.
+ */
+ for (;;)
+ pause();
+ }
+
+ signal(SIGQUIT, SIG_DFL);
+
+ /*
+ * Pretend we are in the foreground again
+ */
+ foreground = 1;
+
+#ifdef TIOCNOTTY
+ {
+ int t = open("/dev/tty", O_RDWR);
+ if (t < 0) {
+ if (errno != ENXIO) /* not an error if already no controlling tty */
+ plog(XLOG_WARNING, "Could not open controlling tty: %m");
+ } else {
+ if (ioctl(t, TIOCNOTTY, 0) < 0 && errno != ENOTTY)
+ plog(XLOG_WARNING, "Could not disassociate tty (TIOCNOTTY): %m");
+ (void) close(t);
+ }
+ }
+#else
+ (void) setpgrp();
+#endif /* TIOCNOTTY */
+
+ return getppid();
+}
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ char *domdot;
+ int ppid = 0;
+ int error;
+
+ /*
+ * Make sure some built-in assumptions are true before we start
+ */
+ assert(sizeof(nfscookie) >= sizeof (unsigned int));
+ assert(sizeof(int) >= 4);
+
+ /*
+ * Set processing status.
+ */
+ amd_state = Start;
+
+ /*
+ * Determine program name
+ */
+ if (argv[0]) {
+ progname = strrchr(argv[0], '/');
+ if (progname && progname[1])
+ progname++;
+ else
+ progname = argv[0];
+ }
+
+ if (!progname)
+ progname = "amd";
+
+ /*
+ * Initialise process id. This is kept
+ * cached since it is used for generating
+ * and using file handles.
+ */
+ mypid = getpid();
+
+ /*
+ * Get local machine name
+ */
+ if (gethostname(hostname, sizeof(hostname)) < 0) {
+ plog(XLOG_FATAL, "gethostname: %m");
+ going_down(1);
+ }
+ /*
+ * Check it makes sense
+ */
+ if (!*hostname) {
+ plog(XLOG_FATAL, "host name is not set");
+ going_down(1);
+ }
+ /*
+ * Partially initialise hostd[]. This
+ * is completed in get_args().
+ */
+ if (domdot = strchr(hostname, '.')) {
+ /*
+ * Hostname already contains domainname.
+ * Split out hostname and domainname
+ * components
+ */
+ *domdot++ = '\0';
+ hostdomain = domdot;
+ }
+ strcpy(hostd, hostname);
+
+ /*
+ * Trap interrupts for shutdowns.
+ */
+ (void) signal(SIGINT, sigterm);
+
+ /*
+ * Hangups tell us to reload the cache
+ */
+ (void) signal(SIGHUP, sighup);
+
+ /*
+ * Trap Terminate so that we can shutdown gracefully (some chance)
+ */
+ (void) signal(SIGTERM, sigterm);
+ /*
+ * Trap Death-of-a-child. These allow us to
+ * pick up the exit status of backgrounded mounts.
+ * See "sched.c".
+ */
+ (void) signal(SIGCHLD, sigchld);
+
+ /*
+ * Fix-up any umask problems. Most systems default
+ * to 002 which is not too convenient for our purposes
+ */
+ orig_umask = umask(0);
+
+ /*
+ * Figure out primary network name
+ */
+ wire = getwire();
+
+ /*
+ * Determine command-line arguments
+ */
+ get_args(argc, argv);
+
+ /*
+ * Get our own IP address so that we
+ * can mount the automounter.
+ */
+ { struct sockaddr_in sin;
+ get_myaddress(&sin);
+ myipaddr.s_addr = sin.sin_addr.s_addr;
+ }
+
+ /*
+ * Now check we are root.
+ */
+ if (geteuid() != 0) {
+ plog(XLOG_FATAL, "Must be root to mount filesystems (euid = %d)", geteuid());
+ going_down(1);
+ }
+
+#ifdef HAS_NIS_MAPS
+ /*
+ * If the domain was specified then bind it here
+ * to circumvent any default bindings that may
+ * be done in the C library.
+ */
+ if (domain && yp_bind(domain)) {
+ plog(XLOG_FATAL, "Can't bind to domain \"%s\"", domain);
+ going_down(1);
+ }
+#endif /* HAS_NIS_MAPS */
+
+#ifdef DEBUG
+ Debug(D_DAEMON)
+#endif /* DEBUG */
+ ppid = daemon_mode();
+
+ sprintf(pid_fsname, "%s:(pid%d)", hostname, mypid);
+
+ do_mapc_reload = clocktime() + ONE_HOUR;
+
+ /*
+ * Register automounter with system
+ */
+ error = mount_automounter(ppid);
+ if (error && ppid)
+ kill(SIGALRM, ppid);
+ going_down(error);
+
+ abort();
+}
diff --git a/usr.sbin/amd/amd/amq_subr.c b/usr.sbin/amd/amd/amq_subr.c
new file mode 100644
index 0000000..cf04d9d
--- /dev/null
+++ b/usr.sbin/amd/amd/amq_subr.c
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq_subr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq_subr.c,v 5.2.2.1 1992/02/09 15:08:18 jsp beta $
+ *
+ */
+/*
+ * Auxilliary routines for amq tool
+ */
+
+#include "am.h"
+#include "amq.h"
+#include <ctype.h>
+
+/*ARGSUSED*/
+voidp
+amqproc_null_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+/*
+ * Return a sub-tree of mounts
+ */
+/*ARGSUSED*/
+amq_mount_tree_p *
+amqproc_mnttree_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static am_node *mp;
+ mp = find_ap(*(char **) argp);
+ return (amq_mount_tree_p *) &mp;
+}
+
+/*
+ * Unmount a single node
+ */
+/*ARGSUSED*/
+voidp
+amqproc_umnt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+ am_node *mp = find_ap(*(char **) argp);
+ if (mp)
+ forcibly_timeout_mp(mp);
+
+ return (voidp) &res;
+}
+
+/*
+ * Return global statistics
+ */
+/*ARGSUSED*/
+amq_mount_stats *
+amqproc_stats_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ return (amq_mount_stats *) &amd_stats;
+}
+
+/*
+ * Return the entire tree of mount nodes
+ */
+/*ARGSUSED*/
+amq_mount_tree_list *
+amqproc_export_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static amq_mount_tree_list aml;
+
+ aml.amq_mount_tree_list_val = (amq_mount_tree_p *) &exported_ap[0];
+ aml.amq_mount_tree_list_len = 1; /* XXX */
+
+ return &aml;
+}
+
+int *
+amqproc_setopt_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static int rc;
+
+ amq_setopt *opt = (amq_setopt *) argp;
+
+ rc = 0;
+ switch (opt->as_opt) {
+ case AMOPT_DEBUG:
+#ifdef DEBUG
+ if (debug_option(opt->as_str))
+ rc = EINVAL;
+#else
+ rc = EINVAL;
+#endif /* DEBUG */
+ break;
+
+ case AMOPT_LOGFILE:
+#ifdef not_yet
+ if (switch_to_logfile(opt->as_str))
+ rc = EINVAL;
+#else
+ rc = EACCES;
+#endif /* not_yet */
+ break;
+
+ case AMOPT_XLOG:
+ if (switch_option(opt->as_str))
+ rc = EINVAL;
+ break;
+
+ case AMOPT_FLUSHMAPC:
+ if (amd_state == Run) {
+ plog(XLOG_INFO, "amq says flush cache");
+ do_mapc_reload = 0;
+ flush_nfs_fhandle_cache((fserver *) 0);
+ flush_srvr_nfs_cache();
+ }
+ break;
+ }
+ return &rc;
+}
+
+amq_mount_info_list *
+amqproc_getmntfs_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+extern qelem mfhead;
+ return (amq_mount_info_list *) &mfhead; /* XXX */
+}
+
+static int ok_security(rqstp)
+struct svc_req *rqstp;
+{
+ struct sockaddr_in *sin;
+
+ sin = svc_getcaller(rqstp->rq_xprt);
+ if (ntohs(sin->sin_port) >= 1024 ||
+ !(sin->sin_addr.s_addr == htonl(0x7f000001) ||
+ sin->sin_addr.s_addr == myipaddr.s_addr)) {
+ char dq[20];
+ plog(XLOG_INFO, "AMQ request from %s.%d DENIED",
+ inet_dquad(dq, sin->sin_addr.s_addr),
+ ntohs(sin->sin_port));
+ return(0);
+ }
+ return(1);
+}
+
+int *
+amqproc_mount_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static int rc;
+ char *s = *(amq_string *) argp;
+ char *cp;
+
+ plog(XLOG_INFO, "amq requested mount of %s", s);
+ /*
+ * Minimalist security check.
+ */
+ if (!ok_security(rqstp)) {
+ rc = EACCES;
+ return &rc;
+ }
+
+ /*
+ * Find end of key
+ */
+ for (cp = (char *) s; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
+ ;
+
+ if (!*cp) {
+ plog(XLOG_INFO, "amqproc_mount: Invalid arguments");
+ rc = EINVAL;
+ return &rc;
+ }
+ *cp++ = '\0';
+
+ /*
+ * Find start of value
+ */
+ while (*cp && isascii(*cp) && isspace(*cp))
+ cp++;
+
+ root_newmap(s, cp, (char *) 0);
+ rc = mount_auto_node(s, (voidp) root_node);
+ if (rc < 0)
+ return 0;
+ return &rc;
+}
+
+amq_string *
+amqproc_getvers_1(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+static amq_string res;
+ res = version;
+ return &res;
+}
+
+/*
+ * XDR routines.
+ */
+bool_t
+xdr_amq_string(xdrs, objp)
+ XDR *xdrs;
+ amq_string *objp;
+{
+ if (!xdr_string(xdrs, objp, AMQ_STRLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_setopt(xdrs, objp)
+ XDR *xdrs;
+ amq_setopt *objp;
+{
+ if (!xdr_enum(xdrs, (enum_t *)&objp->as_opt)) {
+ return (FALSE);
+ }
+ if (!xdr_string(xdrs, &objp->as_str, AMQ_STRLEN)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * More XDR routines - Should be used for OUTPUT ONLY.
+ */
+bool_t
+xdr_amq_mount_tree_node(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+
+ if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_info)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mp->am_path)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, mp->am_link ? &mp->am_link : &mp->am_mnt->mf_mount)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mp->am_mnt->mf_ops->fs_type)) {
+ return (FALSE);
+ }
+ if (!xdr_long(xdrs, &mp->am_stats.s_mtime)) {
+ return (FALSE);
+ }
+ if (!xdr_u_short(xdrs, &mp->am_stats.s_uid)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_getattr)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_lookup)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_readdir)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_readlink)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mp->am_stats.s_statfs)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_subtree(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+
+ if (!xdr_amq_mount_tree_node(xdrs, objp)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_osib, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_tree(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree *objp;
+{
+ am_node *mp = (am_node *) objp;
+ am_node *mnil = 0;
+
+ if (!xdr_amq_mount_tree_node(xdrs, objp)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mnil, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ if (!xdr_pointer(xdrs, (char **)&mp->am_child, sizeof(amq_mount_tree), xdr_amq_mount_subtree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_tree_p(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree_p *objp;
+{
+ if (!xdr_pointer(xdrs, (char **)objp, sizeof(amq_mount_tree), xdr_amq_mount_tree)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_stats(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_stats *objp;
+{
+ if (!xdr_int(xdrs, &objp->as_drops)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_stale)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_mok)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_merr)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &objp->as_uerr)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+
+bool_t
+xdr_amq_mount_tree_list(xdrs, objp)
+ XDR *xdrs;
+ amq_mount_tree_list *objp;
+{
+ if (!xdr_array(xdrs, (char **)&objp->amq_mount_tree_list_val, (u_int *)&objp->amq_mount_tree_list_len, ~0, sizeof(amq_mount_tree_p), xdr_amq_mount_tree_p)) {
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+bool_t
+xdr_amq_mount_info_qelem(xdrs, qhead)
+ XDR *xdrs;
+ qelem *qhead;
+{
+ /*
+ * Compute length of list
+ */
+ mntfs *mf;
+ u_int len = 0;
+ for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+ if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ continue;
+ len++;
+ }
+ xdr_u_int(xdrs, &len);
+
+ /*
+ * Send individual data items
+ */
+ for (mf = LAST(mntfs, qhead); mf != HEAD(mntfs, qhead); mf = PREV(mntfs, mf)) {
+ int up;
+ if (!(mf->mf_ops->fs_flags & FS_AMQINFO))
+ continue;
+
+ if (!xdr_amq_string(xdrs, &mf->mf_ops->fs_type)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_mount)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_info)) {
+ return (FALSE);
+ }
+ if (!xdr_amq_string(xdrs, &mf->mf_server->fs_host)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mf->mf_error)) {
+ return (FALSE);
+ }
+ if (!xdr_int(xdrs, &mf->mf_refc)) {
+ return (FALSE);
+ }
+ if (mf->mf_server->fs_flags & FSF_ERROR)
+ up = 0;
+ else switch (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) {
+ case FSF_DOWN|FSF_VALID: up = 0; break;
+ case FSF_VALID: up = 1; break;
+ default: up = -1; break;
+ }
+ if (!xdr_int(xdrs, &up)) {
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
diff --git a/usr.sbin/amd/amd/clock.c b/usr.sbin/amd/amd/clock.c
new file mode 100644
index 0000000..91e11ee
--- /dev/null
+++ b/usr.sbin/amd/amd/clock.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)clock.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: clock.c,v 5.2.2.1 1992/02/09 15:08:20 jsp beta $
+ *
+ */
+
+/*
+ * Callouts.
+ *
+ * Modelled on kernel object of the same name.
+ * See usual references.
+ *
+ * Use of a heap-based mechanism was rejected:
+ * 1. more complex implementation needed.
+ * 2. not obvious that a list is too slow for Amd.
+ */
+
+#include "am.h"
+
+typedef struct callout callout;
+struct callout {
+ callout *c_next; /* List of callouts */
+ void (*c_fn)(); /* Function to call */
+ voidp c_closure; /* Closure to pass to call */
+ time_t c_time; /* Time of call */
+ int c_id; /* Unique identifier */
+};
+
+static callout callouts; /* List of pending callouts */
+static callout *free_callouts; /* Cache of free callouts */
+static int nfree_callouts; /* Number on free list */
+static int callout_id; /* Next free callout identifier */
+time_t next_softclock; /* Time of next call to softclock() */
+
+/*
+ * Number of callout slots we keep on the free list
+ */
+#define CALLOUT_FREE_SLOP 10
+
+/*
+ * Global assumption: valid id's are non-zero.
+ */
+#define CID_ALLOC() (++callout_id)
+#define CID_UNDEF (0)
+
+static callout *alloc_callout(P_void);
+static callout *alloc_callout()
+{
+ callout *cp = free_callouts;
+ if (cp) {
+ --nfree_callouts;
+ free_callouts = free_callouts->c_next;
+ return cp;
+ }
+ return ALLOC(callout);
+}
+
+static void free_callout P((callout *cp));
+static void free_callout(cp)
+callout *cp;
+{
+ if (nfree_callouts > CALLOUT_FREE_SLOP) {
+ free((voidp) cp);
+ } else {
+ cp->c_next = free_callouts;
+ free_callouts = cp;
+ nfree_callouts++;
+ }
+}
+
+/*
+ * Schedule a callout.
+ *
+ * (*fn)(closure) will be called at clocktime() + secs
+ */
+int timeout P((unsigned int secs, void (*fn)(), voidp closure));
+int timeout(secs, fn, closure)
+unsigned int secs;
+void (*fn)();
+voidp closure;
+{
+ callout *cp, *cp2;
+ time_t t = clocktime() + secs;
+
+ /*
+ * Allocate and fill in a new callout structure
+ */
+ callout *cpnew = alloc_callout();
+ cpnew->c_closure = closure;
+ cpnew->c_fn = fn;
+ cpnew->c_time = t;
+ cpnew->c_id = CID_ALLOC();
+
+ if (t < next_softclock)
+ next_softclock = t;
+
+ /*
+ * Find the correct place in the list
+ */
+ for (cp = &callouts; cp2 = cp->c_next; cp = cp2)
+ if (cp2->c_time >= t)
+ break;
+
+ /*
+ * And link it in
+ */
+ cp->c_next = cpnew;
+ cpnew->c_next = cp2;
+
+ /*
+ * Return callout identifier
+ */
+ return cpnew->c_id;
+}
+
+/*
+ * De-schedule a callout
+ */
+void untimeout P((int id));
+void untimeout(id)
+int id;
+{
+ callout *cp, *cp2;
+ for (cp = &callouts; cp2 = cp->c_next; cp = cp2) {
+ if (cp2->c_id == id) {
+ cp->c_next = cp2->c_next;
+ free_callout(cp2);
+ break;
+ }
+ }
+}
+
+/*
+ * Reschedule after clock changed
+ */
+void reschedule_timeouts P((time_t now, time_t then));
+void reschedule_timeouts(now, then)
+time_t now;
+time_t then;
+{
+ callout *cp;
+
+ for (cp = callouts.c_next; cp; cp = cp->c_next) {
+ if (cp->c_time >= now && cp->c_time <= then) {
+ plog(XLOG_WARNING, "job %d rescheduled to run immediately", cp->c_id);
+#ifdef DEBUG
+ dlog("rescheduling job %d back %d seconds",
+ cp->c_id, cp->c_time - now);
+#endif
+ next_softclock = cp->c_time = now;
+ }
+ }
+}
+
+/*
+ * Clock handler
+ */
+int softclock(P_void);
+int softclock()
+{
+ time_t now;
+ callout *cp;
+
+ do {
+ if (task_notify_todo)
+ do_task_notify();
+
+ now = clocktime();
+
+ /*
+ * While there are more callouts waiting...
+ */
+ while ((cp = callouts.c_next) && cp->c_time <= now) {
+ /*
+ * Extract first from list, save fn & closure and
+ * unlink callout from list and free.
+ * Finally call function.
+ *
+ * The free is done first because
+ * it is quite common that the
+ * function will call timeout()
+ * and try to allocate a callout
+ */
+ void (*fn)() = cp->c_fn;
+ voidp closure = cp->c_closure;
+
+ callouts.c_next = cp->c_next;
+ free_callout(cp);
+#ifdef DEBUG
+ /*dlog("Calling %#x(%#x)", fn, closure);*/
+#endif /* DEBUG */
+ (*fn)(closure);
+ }
+
+ } while (task_notify_todo);
+
+ /*
+ * Return number of seconds to next event,
+ * or 0 if there is no event.
+ */
+ if (cp = callouts.c_next)
+ return cp->c_time - now;
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/efs_ops.c b/usr.sbin/amd/amd/efs_ops.c
new file mode 100644
index 0000000..6630277
--- /dev/null
+++ b/usr.sbin/amd/amd/efs_ops.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)efs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: efs_ops.c,v 5.2.2.1 1992/02/09 15:08:21 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_EFS
+
+/*
+ * Error file system.
+ * This is used as a last resort catchall if
+ * nothing else worked. EFS just returns lots
+ * of error codes, except for unmount which
+ * always works of course.
+ */
+
+/*
+ * EFS file system always matches
+ */
+static char *efs_match(fo)
+am_opts *fo;
+{
+ return strdup("(error-hook)");
+}
+
+/*ARGSUSED*/
+static int efs_fmount(mf)
+mntfs *mf;
+{
+ return ENOENT;
+}
+
+/*ARGSUSED*/
+static int efs_fumount(mf)
+mntfs *mf;
+{
+ /*
+ * Always succeed
+ */
+
+ return 0;
+}
+
+/*
+ * EFS interface to RPC lookup() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+am_node *efs_lookuppn(mp, fname, error_return, op)
+am_node *mp;
+char *fname;
+int *error_return;
+int op;
+{
+ *error_return = ESTALE;
+ return 0;
+}
+
+/*
+ * EFS interface to RPC readdir() routine.
+ * Should never get here in the automounter.
+ * If we do then just give an error.
+ */
+/*ARGSUSED*/
+int efs_readdir(mp, cookie, dp, ep, count)
+am_node *mp;
+nfscookie cookie;
+dirlist *dp;
+entry *ep;
+int count;
+{
+ return ESTALE;
+}
+
+/*
+ * Ops structure
+ */
+am_ops efs_ops = {
+ "error",
+ efs_match,
+ 0, /* efs_init */
+ auto_fmount,
+ efs_fmount,
+ auto_fumount,
+ efs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* efs_readlink */
+ 0, /* efs_mounted */
+ 0, /* efs_umounted */
+ find_afs_srvr,
+ FS_DISCARD
+};
+
+#endif /* HAS_EFS */
diff --git a/usr.sbin/amd/amd/get_args.c b/usr.sbin/amd/amd/get_args.c
new file mode 100644
index 0000000..0567d5d
--- /dev/null
+++ b/usr.sbin/amd/amd/get_args.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)get_args.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: get_args.c,v 5.2.2.1 1992/02/09 15:08:23 jsp beta $
+ *
+ */
+
+/*
+ * Argument decode
+ */
+
+#include "am.h"
+#ifdef HAS_SYSLOG
+#include <syslog.h>
+#endif /* HAS_SYSLOG */
+#include <sys/stat.h>
+
+extern int optind;
+extern char *optarg;
+
+#if defined(DEBUG) && defined(PARANOID)
+char **gargv;
+#endif /* defined(DEBUG) && defined(PARANOID) */
+int restart_existing_mounts;
+int print_pid;
+int normalize_hosts;
+char *karch; /* Kernel architecture */
+char *cluster; /* Cluster name */
+#ifdef HAS_NIS_MAPS
+char *domain; /* YP domain */
+#endif /* HAS_NIS_MAPS */
+#ifdef UPDATE_MTAB
+char *mtab;
+#endif /* UPDATE_MTAB */
+int afs_timeo = -1;
+int afs_retrans = -1;
+int am_timeo = AM_TTL;
+int am_timeo_w = AM_TTL_W;
+
+#ifdef DEBUG
+/*
+ * List of debug options.
+ */
+static struct opt_tab dbg_opt[] = {
+ { "all", D_ALL }, /* All */
+ { "amq", D_AMQ }, /* Register for AMQ program */
+ { "daemon", D_DAEMON }, /* Enter daemon mode */
+ { "full", D_FULL }, /* Program trace */
+ { "mem", D_MEM }, /* Trace memory allocations */
+ { "mtab", D_MTAB }, /* Use local mtab file */
+ { "str", D_STR }, /* Debug string munging */
+ { "test", D_TEST }, /* Full debug - but no daemon */
+ { "trace", D_TRACE }, /* Protocol trace */
+ { 0, 0 }
+};
+
+int debug_flags = D_AMQ /* Register AMQ */
+ |D_DAEMON /* Enter daemon mode */
+ ;
+
+/*
+ * Switch on/off debug options
+ */
+int debug_option(opt)
+char *opt;
+{
+ return cmdoption(opt, dbg_opt, &debug_flags);
+}
+#endif /* DEBUG */
+
+void get_args(c, v)
+int c;
+char *v[];
+{
+ int opt_ch;
+ int usage = 0;
+ char *logfile = 0;
+ char *sub_domain = 0;
+
+ while ((opt_ch = getopt(c, v, "mnprva:c:d:h:k:l:t:w:x:y:C:D:")) != EOF)
+ switch (opt_ch) {
+ case 'a':
+ if (*optarg != '/') {
+ fprintf(stderr, "%s: -a option must begin with a '/'\n",
+ progname);
+ exit(1);
+ }
+ auto_dir = optarg;
+ break;
+
+ case 'c':
+ am_timeo = atoi(optarg);
+ if (am_timeo <= 0)
+ am_timeo = AM_TTL;
+ break;
+
+ case 'd':
+ sub_domain = optarg;
+ break;
+
+ case 'h':
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+ host_helper = optarg;
+#else
+ plog(XLOG_USER, "-h: option ignored. HOST_EXEC is not enabled.");
+ break;
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+ case 'k':
+ karch = optarg;
+ break;
+
+ case 'l':
+ logfile = optarg;
+ break;
+
+ case 'm':
+ plog(XLOG_USER, "The -m option is no longer supported.");
+ plog(XLOG_USER, "... Use `ypcat -k am.master` on the command line instead");
+ break;
+
+ case 'n':
+ normalize_hosts = 1;
+ break;
+
+ case 'p':
+ print_pid = 1;
+ break;
+
+ case 'r':
+ restart_existing_mounts = 1;
+ break;
+
+ case 't':
+ /* timeo.retrans */
+ { char *dot = strchr(optarg, '.');
+ if (dot) *dot = '\0';
+ if (*optarg) {
+ afs_timeo = atoi(optarg);
+ }
+ if (dot) {
+ afs_retrans = atoi(dot+1);
+ *dot = '.';
+ }
+ }
+ break;
+
+ case 'v':
+ fprintf(stderr, "%s%s (%s-endian).\n", copyright, version, endian);
+ fputs("Map support for: ", stderr);
+ mapc_showtypes(stderr);
+ fputs(".\nFS: ", stderr);
+ ops_showfstypes(stderr);
+ fputs(".\n", stderr);
+ fprintf(stderr, "Primary network is %s.\n", wire);
+ exit(0);
+ break;
+
+ case 'w':
+ am_timeo_w = atoi(optarg);
+ if (am_timeo_w <= 0)
+ am_timeo_w = AM_TTL_W;
+ break;
+
+ case 'x':
+ usage += switch_option(optarg);
+ break;
+
+ case 'y':
+#ifdef HAS_NIS_MAPS
+ domain = optarg;
+#else
+ plog(XLOG_USER, "-y: option ignored. No NIS support available.");
+#endif /* HAS_NIS_MAPS */
+ break;
+
+ case 'C':
+ cluster = optarg;
+ break;
+
+ case 'D':
+#ifdef DEBUG
+ usage += debug_option(optarg);
+#else
+ fprintf(stderr, "%s: not compiled with DEBUG option -- sorry.\n", progname);
+#endif /* DEBUG */
+ break;
+
+ default:
+ usage = 1;
+ break;
+ }
+
+ if (xlog_level_init == ~0) {
+ (void) switch_option("");
+#ifdef DEBUG
+ usage += switch_option("debug");
+#endif /* DEBUG */
+ } else {
+#ifdef DEBUG
+ usage += switch_option("debug");
+#endif /* DEBUG */
+ }
+
+ if (usage)
+ goto show_usage;
+
+ while (optind <= c-2) {
+ char *dir = v[optind++];
+ char *map = v[optind++];
+ char *opts = "";
+ if (v[optind] && *v[optind] == '-')
+ opts = &v[optind++][1];
+
+ root_newmap(dir, opts, map);
+ }
+
+ if (optind == c) {
+#ifdef hpux
+ /*
+ * HP-UX can't handle ./mtab
+ * That system is sick - really.
+ */
+#ifdef DEBUG
+ debug_option("nomtab");
+#endif /* DEBUG */
+#endif /* hpux */
+
+ /*
+ * Append domain name to hostname.
+ * sub_domain overrides hostdomain
+ * if given.
+ */
+ if (sub_domain)
+ hostdomain = sub_domain;
+ if (*hostdomain == '.')
+ hostdomain++;
+ strcat(hostd, ".");
+ strcat(hostd, hostdomain);
+
+#ifdef UPDATE_MTAB
+#ifdef DEBUG
+ if (debug_flags & D_MTAB)
+ mtab = DEBUG_MTAB;
+ else
+#endif /* DEBUG */
+ mtab = MOUNTED;
+#else
+#ifdef DEBUG
+ { if (debug_flags & D_MTAB) {
+ dlog("-D mtab option ignored");
+ } }
+#endif /* DEBUG */
+#endif /* UPDATE_MTAB */
+
+ if (switch_to_logfile(logfile) != 0)
+ plog(XLOG_USER, "Cannot switch logfile");
+
+ /*
+ * If the kernel architecture was not specified
+ * then use the machine architecture.
+ */
+ if (karch == 0)
+ karch = arch;
+
+ if (cluster == 0)
+ cluster = hostdomain;
+
+ if (afs_timeo <= 0)
+ afs_timeo = AFS_TIMEO;
+ if (afs_retrans <= 0)
+ afs_retrans = AFS_RETRANS;
+ if (afs_retrans <= 0)
+ afs_retrans = 3; /* XXX */
+ return;
+ }
+
+show_usage:
+ fprintf(stderr,
+"Usage: %s [-mnprv] [-a mnt_point] [-c cache_time] [-d domain]\n\
+\t[-k kernel_arch] [-l logfile|\"syslog\"] [-t afs_timeout]\n\
+\t[-w wait_timeout] [-C cluster_name]", progname);
+
+#if defined(HAS_HOST) && defined(HOST_EXEC)
+ fputs(" [-h host_helper]\n", stderr);
+#endif /* defined(HAS_HOST) && defined(HOST_EXEC) */
+
+#ifdef HAS_NIS_MAPS
+ fputs(" [-y nis-domain]\n", stderr);
+#else
+ fputc('\n', stderr);
+#endif /* HAS_NIS_MAPS */
+
+ show_opts('x', xlog_opt);
+#ifdef DEBUG
+ show_opts('D', dbg_opt);
+#endif /* DEBUG */
+ fprintf(stderr, "\t{directory mapname [-map_options]} ...\n");
+ exit(1);
+}
diff --git a/usr.sbin/amd/amd/host_ops.c b/usr.sbin/amd/amd/host_ops.c
new file mode 100644
index 0000000..ba0dedb
--- /dev/null
+++ b/usr.sbin/amd/amd/host_ops.c
@@ -0,0 +1,681 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)host_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: host_ops.c,v 5.2.2.2 1992/05/31 16:36:08 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_HOST
+
+#include "mount.h"
+#include <sys/stat.h>
+
+/*
+ * NFS host file system.
+ * Mounts all exported filesystems from a given host.
+ * This has now degenerated into a mess but will not
+ * be rewritten. Amd 6 will support the abstractions
+ * needed to make this work correctly.
+ */
+
+/*
+ * Define HOST_RPC_UDP to use dgram instead of stream RPC.
+ * Datagrams are generally much faster.
+ */
+/*#define HOST_RPC_UDP*/
+
+/*
+ * Define HOST_MKDIRS to make Amd automatically try
+ * to create the mount points.
+ */
+#define HOST_MKDIRS
+
+/*
+ * Determine the mount point
+ */
+#define MAKE_MNTPT(mntpt, ex, mf) { \
+ if (strcmp((ex)->ex_dir, "/") == 0) \
+ strcpy((mntpt), (mf)->mf_mount); \
+ else \
+ sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \
+}
+
+/*
+ * Execute needs the same as NFS plus a helper command
+ */
+static char *host_match P((am_opts *fo));
+static char *host_match(fo)
+am_opts *fo;
+{
+#ifdef HOST_EXEC
+ if (!host_helper) {
+ plog(XLOG_USER, "No host helper command given");
+ return FALSE;
+ }
+#endif /* HOST_EXEC */
+
+ /*
+ * Make sure rfs is specified to keep nfs_match happy...
+ */
+ if (!fo->opt_rfs)
+ fo->opt_rfs = "/";
+
+
+ return (*nfs_ops.fs_match)(fo);
+}
+
+static int host_init(mf)
+mntfs *mf;
+{
+ if (strchr(mf->mf_info, ':') == 0)
+ return ENOENT;
+ return 0;
+}
+
+/*
+ * Two implementations:
+ * HOST_EXEC gets you the external version. The program specified with
+ * the -h option is called. The external program is not published...
+ * roll your own.
+ *
+ * Otherwise you get the native version. Faster but makes the program
+ * bigger.
+ */
+
+#ifndef HOST_EXEC
+
+static bool_t
+xdr_pri_free(xdr_args, args_ptr)
+xdrproc_t xdr_args;
+caddr_t args_ptr;
+{
+ XDR xdr;
+ xdr.x_op = XDR_FREE;
+ return ((*xdr_args)(&xdr, args_ptr));
+}
+
+static int do_mount P((fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
+static int do_mount(fhp, dir, fs_name, opts, mf)
+fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+ struct stat stb;
+#ifdef DEBUG
+ dlog("host: mounting fs %s on %s\n", fs_name, dir);
+#endif /* DEBUG */
+#ifdef HOST_MKDIRS
+ (void) mkdirs(dir, 0555);
+#endif /* HOST_MKDIRS */
+ if (stat(dir, &stb) < 0 || (stb.st_mode & S_IFMT) != S_IFDIR) {
+ plog(XLOG_ERROR, "No mount point for %s - skipping", dir);
+ return ENOENT;
+ }
+
+ return mount_nfs_fh(fhp, dir, fs_name, opts, mf);
+}
+
+static int sortfun P((exports *a, exports *b));
+static int sortfun(a, b)
+exports *a,*b;
+{
+ return strcmp((*a)->ex_dir, (*b)->ex_dir);
+}
+
+/*
+ * Get filehandle
+ */
+static int fetch_fhandle P((CLIENT *client, char *dir, fhstatus *fhp));
+static int fetch_fhandle(client, dir, fhp)
+CLIENT *client;
+char *dir;
+fhstatus *fhp;
+{
+ struct timeval tv;
+ enum clnt_stat clnt_stat;
+
+ /*
+ * Pick a number, any number...
+ */
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+#ifdef DEBUG
+ dlog("Fetching fhandle for %s", dir);
+#endif /* DEBUG */
+ /*
+ * Call the mount daemon on the remote host to
+ * get the filehandle.
+ */
+ clnt_stat = clnt_call(client, MOUNTPROC_MNT, xdr_dirpath, &dir, xdr_fhstatus, fhp, tv);
+ if (clnt_stat != RPC_SUCCESS) {
+ extern char *clnt_sperrno();
+ char *msg = clnt_sperrno(clnt_stat);
+ plog(XLOG_ERROR, "mountd rpc failed: %s", msg);
+ return EIO;
+ }
+ /*
+ * Check status of filehandle
+ */
+ if (fhp->fhs_status) {
+#ifdef DEBUG
+ errno = fhp->fhs_status;
+ dlog("fhandle fetch failed: %m");
+#endif /* DEBUG */
+ return fhp->fhs_status;
+ }
+ return 0;
+}
+
+/*
+ * Scan mount table to see if something already mounted
+ */
+static int already_mounted P((mntlist *mlist, char*dir));
+static int already_mounted(mlist, dir)
+mntlist *mlist;
+char *dir;
+{
+ mntlist *ml;
+
+ for (ml = mlist; ml; ml = ml->mnext)
+ if (strcmp(ml->mnt->mnt_dir, dir) == 0)
+ return 1;
+ return 0;
+}
+
+/*
+ * Mount the export tree from a host
+ */
+static int host_fmount P((mntfs *mf));
+static int host_fmount(mf)
+mntfs *mf;
+{
+ struct timeval tv2;
+ CLIENT *client;
+ enum clnt_stat clnt_stat;
+ int n_export;
+ int j, k;
+ exports exlist = 0, ex;
+ exports *ep = 0;
+ fhstatus *fp = 0;
+ char *host = mf->mf_server->fs_host;
+ int error = 0;
+ struct sockaddr_in sin;
+ int sock = RPC_ANYSOCK;
+ int ok = FALSE;
+ mntlist *mlist;
+ char fs_name[MAXPATHLEN], *rfs_dir;
+ char mntpt[MAXPATHLEN];
+ struct timeval tv;
+ tv.tv_sec = 10; tv.tv_usec = 0;
+
+ /*
+ * Read the mount list
+ */
+ mlist = read_mtab(mf->mf_mount);
+
+ /*
+ * Unlock the mount list
+ */
+ unlock_mntlist();
+
+ /*
+ * Take a copy of the server address
+ */
+ sin = *mf->mf_server->fs_ip;
+
+ /*
+ * Zero out the port - make sure we recompute
+ */
+ sin.sin_port = 0;
+ /*
+ * Make a client end-point.
+ * Try TCP first
+ */
+ if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+ (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
+ plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+ error = EIO;
+ goto out;
+ }
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ goto out;
+ }
+
+ client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+ dlog("Fetching export list from %s", host);
+#endif /* DEBUG */
+
+ /*
+ * Fetch the export list
+ */
+ tv2.tv_sec = 10; tv2.tv_usec = 0;
+ clnt_stat = clnt_call(client, MOUNTPROC_EXPORT, xdr_void, 0, xdr_exports, &exlist, tv2);
+ if (clnt_stat != RPC_SUCCESS) {
+ /*clnt_perror(client, "rpc");*/
+ error = EIO;
+ goto out;
+ }
+
+ /*
+ * Figure out how many exports were returned
+ */
+ for (n_export = 0, ex = exlist; ex; ex = ex->ex_next) {
+ /*printf("export %s\n", ex->ex_dir);*/
+ n_export++;
+ }
+#ifdef DEBUG
+ /*dlog("%d exports returned\n", n_export);*/
+#endif /* DEBUG */
+
+ /*
+ * Allocate an array of pointers into the list
+ * so that they can be sorted. If the filesystem
+ * is already mounted then ignore it.
+ */
+ ep = (exports *) xmalloc(n_export * sizeof(exports));
+ for (j = 0, ex = exlist; ex; ex = ex->ex_next) {
+ MAKE_MNTPT(mntpt, ex, mf);
+ if (!already_mounted(mlist, mntpt))
+ ep[j++] = ex;
+ }
+ n_export = j;
+
+ /*
+ * Sort into order.
+ * This way the mounts are done in order down the tree,
+ * instead of any random order returned by the mount
+ * daemon (the protocol doesn't specify...).
+ */
+ qsort(ep, n_export, sizeof(exports), sortfun);
+
+ /*
+ * Allocate an array of filehandles
+ */
+ fp = (fhstatus *) xmalloc(n_export * sizeof(fhstatus));
+
+ /*
+ * Try to obtain filehandles for each directory.
+ * If a fetch fails then just zero out the array
+ * reference but discard the error.
+ */
+ for (j = k = 0; j < n_export; j++) {
+ /* Check and avoid a duplicated export entry */
+ if (j > k && ep[k] && strcmp(ep[j]->ex_dir, ep[k]->ex_dir) == 0) {
+#ifdef DEBUG
+ dlog("avoiding dup fhandle requested for %s", ep[j]->ex_dir);
+#endif
+ ep[j] = 0;
+ } else {
+ k = j;
+ if (error = fetch_fhandle(client, ep[j]->ex_dir, &fp[j]))
+ ep[j] = 0;
+ }
+ }
+
+ /*
+ * Mount each filesystem for which we have a filehandle.
+ * If any of the mounts succeed then mark "ok" and return
+ * error code 0 at the end. If they all fail then return
+ * the last error code.
+ */
+ strncpy(fs_name, mf->mf_info, sizeof(fs_name));
+ if ((rfs_dir = strchr(fs_name, ':')) == (char *) 0) {
+ plog(XLOG_FATAL, "host_fmount: mf_info has no colon");
+ error = EINVAL;
+ goto out;
+ }
+ ++rfs_dir;
+ for (j = 0; j < n_export; j++) {
+ ex = ep[j];
+ if (ex) {
+ strcpy(rfs_dir, ex->ex_dir);
+ MAKE_MNTPT(mntpt, ex, mf);
+ if (do_mount(&fp[j], mntpt, fs_name, mf->mf_mopts, mf) == 0)
+ ok = TRUE;
+ }
+ }
+
+ /*
+ * Clean up and exit
+ */
+out:
+ discard_mntlist(mlist);
+ if (ep)
+ free(ep);
+ if (fp)
+ free(fp);
+ if (client)
+ clnt_destroy(client);
+ if (exlist)
+ xdr_pri_free(xdr_exports, &exlist);
+ if (ok)
+ return 0;
+ return error;
+}
+
+/*
+ * Return true if pref is a directory prefix of dir.
+ *
+ * TODO:
+ * Does not work if pref is "/".
+ */
+static int directory_prefix P((char *pref, char *dir));
+static int directory_prefix(pref, dir)
+char *pref;
+char *dir;
+{
+ int len = strlen(pref);
+ if (strncmp(pref, dir, len) != 0)
+ return FALSE;
+ if (dir[len] == '/' || dir[len] == '\0')
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * Unmount a mount tree
+ */
+static int host_fumount P((mntfs *mf));
+static int host_fumount(mf)
+mntfs *mf;
+{
+ mntlist *ml, *mprev;
+ int xerror = 0;
+
+ /*
+ * Read the mount list
+ */
+ mntlist *mlist = read_mtab(mf->mf_mount);
+
+ /*
+ * Unlock the mount list
+ */
+ unlock_mntlist();
+
+ /*
+ * Reverse list...
+ */
+ ml = mlist;
+ mprev = 0;
+ while (ml) {
+ mntlist *ml2 = ml->mnext;
+ ml->mnext = mprev;
+ mprev = ml;
+ ml = ml2;
+ }
+ mlist = mprev;
+
+ /*
+ * Unmount all filesystems...
+ */
+ for (ml = mlist; ml && !xerror; ml = ml->mnext) {
+ char *dir = ml->mnt->mnt_dir;
+ if (directory_prefix(mf->mf_mount, dir)) {
+ int error;
+#ifdef DEBUG
+ dlog("host: unmounts %s", dir);
+#endif /* DEBUG */
+ /*
+ * Unmount "dir"
+ */
+ error = UMOUNT_FS(dir);
+ /*
+ * Keep track of errors
+ */
+ if (error) {
+ if (!xerror)
+ xerror = error;
+ if (error != EBUSY) {
+ errno = error;
+ plog("Tree unmount of %s failed: %m", ml->mnt->mnt_dir);
+ }
+ } else {
+#ifdef HOST_MKDIRS
+ (void) rmdirs(dir);
+#endif /* HOST_MKDIRS */
+ }
+ }
+ }
+
+ /*
+ * Throw away mount list
+ */
+ discard_mntlist(mlist);
+
+ /*
+ * Try to remount, except when we are shutting down.
+ */
+ if (xerror && amd_state != Finishing) {
+ xerror = host_fmount(mf);
+ if (!xerror) {
+ /*
+ * Don't log this - it's usually too verbose
+ plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
+ */
+ xerror = EBUSY;
+ }
+ }
+ return xerror;
+}
+
+/*
+ * Tell mountd we're done.
+ * This is not quite right, because we may still
+ * have other filesystems mounted, but the existing
+ * mountd protocol is badly broken anyway.
+ */
+static void host_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+ mntfs *mf = mp->am_mnt;
+ char *host;
+ CLIENT *client;
+ enum clnt_stat clnt_stat;
+ struct sockaddr_in sin;
+ int sock = RPC_ANYSOCK;
+ struct timeval tv;
+ tv.tv_sec = 10; tv.tv_usec = 0;
+
+ if (mf->mf_error || mf->mf_refc > 1 || ! mf->mf_server)
+ return;
+
+ host = mf->mf_server->fs_host;
+ sin = *mf->mf_server->fs_ip;
+
+ /*
+ * Zero out the port - make sure we recompute
+ */
+ sin.sin_port = 0;
+ /*
+ * Make a client end-point.
+ * Try TCP first
+ */
+ if ((client = clnttcp_create(&sin, MOUNTPROG, MOUNTVERS, &sock, 0, 0)) == NULL &&
+ (client = clntudp_create(&sin, MOUNTPROG, MOUNTVERS, tv, &sock)) == NULL) {
+ plog(XLOG_ERROR, "Failed to make rpc connection to mountd on %s", host);
+ goto out;
+ }
+
+ if (!nfs_auth) {
+ if (make_nfs_auth())
+ goto out;
+ }
+
+ client->cl_auth = nfs_auth;
+
+#ifdef DEBUG
+ dlog("Unmounting all from %s", host);
+#endif /* DEBUG */
+
+ clnt_stat = clnt_call(client, MOUNTPROC_UMNTALL, xdr_void, 0, xdr_void, 0, tv);
+ if (clnt_stat != RPC_SUCCESS && clnt_stat != RPC_SYSTEMERROR) {
+ /* RPC_SYSTEMERROR seems to be returned for no good reason ...*/
+ extern char *clnt_sperrno();
+ char *msg = clnt_sperrno(clnt_stat);
+ plog(XLOG_ERROR, "unmount all from %s rpc failed: %s", host, msg, clnt_stat);
+ goto out;
+ }
+
+out:
+ if (client)
+ clnt_destroy(client);
+
+#endif /* INFORM_MOUNTD */
+}
+
+
+#else /* HOST_EXEC */
+
+static int host_exec P((char*op, char*host, char*fs, char*opts));
+static int host_exec(op, host, fs, opts)
+char *op;
+char *host;
+char *fs;
+char *opts;
+{
+ int error;
+ char *argv[7];
+
+ /*
+ * Build arg vector
+ */
+ argv[0] = host_helper;
+ argv[1] = host_helper;
+ argv[2] = op;
+ argv[3] = host;
+ argv[4] = fs;
+ argv[5] = opts && *opts ? opts : "rw,default";
+ argv[6] = 0;
+
+ /*
+ * Put stdout to stderr
+ */
+ (void) fclose(stdout);
+ (void) dup(fileno(logfp));
+ if (fileno(logfp) != fileno(stderr)) {
+ (void) fclose(stderr);
+ (void) dup(fileno(logfp));
+ }
+ /*
+ * Try the exec
+ */
+#ifdef DEBUG
+ Debug(D_FULL) {
+ char **cp = argv;
+ plog(XLOG_DEBUG, "executing (un)mount command...");
+ while (*cp) {
+ plog(XLOG_DEBUG, "arg[%d] = '%s'", cp-argv, *cp);
+ cp++;
+ }
+ }
+#endif /* DEBUG */
+ if (argv[0] == 0 || argv[1] == 0) {
+ errno = EINVAL;
+ plog(XLOG_USER, "1st/2nd args missing to (un)mount program");
+ } else {
+ (void) execv(argv[0], argv+1);
+ }
+ /*
+ * Save error number
+ */
+ error = errno;
+ plog(XLOG_ERROR, "exec %s failed: %m", argv[0]);
+
+ /*
+ * Return error
+ */
+ return error;
+}
+
+static int host_mount P((am_node *mp));
+static int host_mount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ return host_exec("mount", mf->mf_server->fs_host, mf->mf_mount, mf->mf_opts);
+}
+
+static int host_umount P((am_node *mp));
+static int host_umount(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+
+ return host_exec("unmount", mf->mf_server->fs_host, mf->mf_mount, "xxx");
+}
+
+#endif /* HOST_EXEC */
+
+/*
+ * Ops structure
+ */
+am_ops host_ops = {
+ "host",
+ host_match,
+ host_init,
+ auto_fmount,
+ host_fmount,
+ auto_fumount,
+ host_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* host_readlink */
+ 0, /* host_mounted */
+#ifdef HOST_EXEC
+ 0, /* host_umounted */
+#else
+ host_umounted,
+#endif
+ find_nfs_srvr,
+ FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_HOST */
diff --git a/usr.sbin/amd/amd/ifs_ops.c b/usr.sbin/amd/amd/ifs_ops.c
new file mode 100644
index 0000000..14df832
--- /dev/null
+++ b/usr.sbin/amd/amd/ifs_ops.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)ifs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: ifs_ops.c,v 5.2.2.1 1992/02/09 15:08:26 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_IFS
+
+/*
+ * Inheritance file system.
+ * This implements a filesystem restart.
+ *
+ * This is a *gross* hack - it knows far too
+ * much about the way other parts of the
+ * sytem work. See restart.c too.
+ */
+static char not_a_filesystem[] = "Attempting to inherit not-a-filesystem";
+/*
+ * This should never be called.
+ */
+/*ARGSUSED*/
+static char *ifs_match P((am_opts *fo));
+static char *ifs_match(fo)
+am_opts *fo;
+{
+ plog(XLOG_FATAL, "ifs_match called!");
+ return 0;
+}
+
+static int ifs_init P((mntfs *mf));
+static int ifs_init(mf)
+mntfs *mf;
+{
+ mntfs *mf_link = (mntfs *) mf->mf_private;
+ if (mf_link == 0) {
+ plog(XLOG_FATAL, not_a_filesystem);
+ return EINVAL;
+ }
+#ifdef notdef
+ /*
+ * Fill in attribute fields
+ */
+ mf_link->mf_fattr.type = NFLNK;
+ mf_link->mf_fattr.mode = NFSMODE_LNK | 0777;
+ mf_link->mf_fattr.nlink = 1;
+ mf_link->mf_fattr.size = MAXPATHLEN / 4;
+#endif
+ if (mf_link->mf_ops->fs_init)
+ return (*mf_link->mf_ops->fs_init)(mf_link);
+ return 0;
+}
+
+static mntfs *ifs_inherit P((mntfs *mf));
+static mntfs *ifs_inherit(mf)
+mntfs *mf;
+{
+ /*
+ * Take the linked mount point and
+ * propogate.
+ */
+ mntfs *mf_link = (mntfs *) mf->mf_private;
+ if (mf_link == 0) {
+ plog(XLOG_FATAL, not_a_filesystem);
+ return 0; /*XXX*/
+ }
+
+ mf_link->mf_fo = mf->mf_fo;
+#ifdef notdef
+ mf_link->mf_fattr.fileid = mf->mf_fattr.fileid;
+#endif /* notdef */
+
+ /*
+ * Discard the old map.
+ * Don't call am_unmounted since this
+ * node was never really mounted in the
+ * first place.
+ */
+ mf->mf_private = 0;
+ free_mntfs(mf);
+ /*
+ * Free the dangling reference
+ * to the mount link.
+ */
+ free_mntfs(mf_link);
+ /*
+ * Get a hold of the other entry
+ */
+ mf_link->mf_flags &= ~MFF_RESTART;
+
+ /* Say what happened */
+ plog(XLOG_INFO, "restarting %s on %s", mf_link->mf_info, mf_link->mf_mount);
+
+ return mf_link;
+}
+
+static int ifs_mount P((am_node *mp));
+static int ifs_mount(mp)
+am_node *mp;
+{
+ mntfs *newmf = ifs_inherit(mp->am_mnt);
+ if (newmf) {
+ mp->am_mnt = newmf;
+ /*
+ * XXX - must do the am_mounted call here
+ */
+ if (newmf->mf_ops->fs_flags & FS_MBACKGROUND)
+ am_mounted(mp);
+
+ new_ttl(mp);
+ return 0;
+ }
+ return EINVAL;
+}
+
+static int ifs_fmount P((mntfs *mf));
+static int ifs_fmount(mf)
+mntfs *mf;
+{
+ am_node *mp = find_mf(mf);
+ if (mp)
+ return ifs_mount(mp);
+ return ifs_inherit(mf) ? 0 : EINVAL;
+}
+
+/*ARGSUSED*/
+static int ifs_fumount P((mntfs *mf));
+static int ifs_fumount(mf)
+mntfs *mf;
+{
+ /*
+ * Always succeed
+ */
+ return 0;
+}
+
+/*
+ * Ops structure
+ */
+am_ops ifs_ops = {
+ "inherit",
+ ifs_match,
+ ifs_init,
+ ifs_mount,
+ ifs_fmount,
+ auto_fumount,
+ ifs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* ifs_readlink */
+ 0, /* ifs_mounted */
+ 0, /* ifs_umounted */
+ find_afs_srvr,
+ FS_DISCARD
+};
+
+#endif /* HAS_IFS */
diff --git a/usr.sbin/amd/amd/info_file.c b/usr.sbin/amd/amd/info_file.c
new file mode 100644
index 0000000..c43b2a7
--- /dev/null
+++ b/usr.sbin/amd/amd/info_file.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_file.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_file.c,v 5.2.2.1 1992/02/09 15:08:28 jsp beta $
+ *
+ */
+
+/*
+ * Get info from file
+ */
+
+#include "am.h"
+
+#ifdef HAS_FILE_MAPS
+#include <ctype.h>
+#include <sys/stat.h>
+
+#define MAX_LINE_LEN 2048
+
+static int read_line P((char *buf, int size, FILE *fp));
+static int read_line(buf, size, fp)
+char *buf;
+int size;
+FILE *fp;
+{
+ int done = 0;
+
+ do {
+ while (fgets(buf, size, fp)) {
+ int len = strlen(buf);
+ done += len;
+ if (len > 1 && buf[len-2] == '\\' &&
+ buf[len-1] == '\n') {
+ int ch;
+ buf += len - 2;
+ size -= len - 2;
+ *buf = '\n'; buf[1] = '\0';
+ /*
+ * Skip leading white space on next line
+ */
+ while ((ch = getc(fp)) != EOF &&
+ isascii(ch) && isspace(ch))
+ ;
+ (void) ungetc(ch, fp);
+ } else {
+ return done;
+ }
+ }
+ } while (size > 0 && !feof(fp));
+
+ return done;
+}
+
+/*
+ * Try to locate a key in a file
+ */
+static int search_or_reload_file P((FILE *fp, char *map, char *key, char **val, mnt_map *m, void (*fn)(mnt_map *m, char*, char*)));
+static int search_or_reload_file(fp, map, key, val, m, fn)
+FILE *fp;
+char *map;
+char *key;
+char **val;
+mnt_map *m;
+void (*fn) P((mnt_map*, char*, char*));
+{
+ char key_val[MAX_LINE_LEN];
+ int chuck = 0;
+ int line_no = 0;
+
+ while (read_line(key_val, sizeof(key_val), fp)) {
+ char *kp;
+ char *cp;
+ char *hash;
+ int len = strlen(key_val);
+ line_no++;
+
+ /*
+ * Make sure we got the whole line
+ */
+ if (key_val[len-1] != '\n') {
+ plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
+ chuck = 1;
+ } else {
+ key_val[len-1] = '\0';
+ }
+
+ /*
+ * Strip comments
+ */
+ hash = strchr(key_val, '#');
+ if (hash)
+ *hash = '\0';
+
+ /*
+ * Find start of key
+ */
+ for (kp = key_val; *kp && isascii(*kp) && isspace(*kp); kp++)
+ ;
+
+ /*
+ * Ignore blank lines
+ */
+ if (!*kp)
+ goto again;
+
+ /*
+ * Find end of key
+ */
+ for (cp = kp; *cp&&(!isascii(*cp)||!isspace(*cp)); cp++)
+ ;
+
+ /*
+ * Check whether key matches
+ */
+ if (*cp)
+ *cp++ = '\0';
+
+ if (fn || (*key == *kp && strcmp(key, kp) == 0)) {
+ while (*cp && isascii(*cp) && isspace(*cp))
+ cp++;
+ if (*cp) {
+ /*
+ * Return a copy of the data
+ */
+ char *dc = strdup(cp);
+ if (fn) {
+ (*fn)(m, strdup(kp), dc);
+ } else {
+ *val = dc;
+#ifdef DEBUG
+ dlog("%s returns %s", key, dc);
+#endif /* DEBUG */
+ }
+ if (!fn)
+ return 0;
+ } else {
+ plog(XLOG_USER, "%s: line %d has no value field", map, line_no);
+ }
+ }
+
+again:
+ /*
+ * If the last read didn't get a whole line then
+ * throw away the remainder before continuing...
+ */
+ if (chuck) {
+ while (fgets(key_val, sizeof(key_val), fp) &&
+ !strchr(key_val, '\n'))
+ ;
+ chuck = 0;
+ }
+ }
+
+ return fn ? 0 : ENOENT;
+}
+
+static FILE *file_open P((char *map, time_t *tp));
+static FILE *file_open(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = fopen(map, "r");
+ if (mapf && tp) {
+ struct stat stb;
+ if (fstat(fileno(mapf), &stb) < 0)
+ *tp = clocktime();
+ else
+ *tp = stb.st_mtime;
+ }
+ return mapf;
+}
+
+int file_init P((char *map, time_t *tp));
+int file_init(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = file_open(map, tp);
+ if (mapf) {
+ (void) fclose(mapf);
+ return 0;
+ }
+ return errno;
+}
+
+int file_reload P((mnt_map *m, char *map, void (*fn)()));
+int file_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ FILE *mapf = file_open(map, (time_t *) 0);
+ if (mapf) {
+ int error = search_or_reload_file(mapf, map, 0, 0, m, fn);
+ (void) fclose(mapf);
+ return error;
+ }
+
+ return errno;
+}
+
+int file_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int file_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ time_t t;
+ FILE *mapf = file_open(map, &t);
+ if (mapf) {
+ int error;
+ if (*tp < t) {
+ *tp = t;
+ error = -1;
+ } else {
+ error = search_or_reload_file(mapf, map, key, pval, 0, 0);
+ }
+ (void) fclose(mapf);
+ return error;
+ }
+
+ return errno;
+}
+
+int file_mtime P((char *map, time_t *tp));
+int file_mtime(map, tp)
+char *map;
+time_t *tp;
+{
+ FILE *mapf = file_open(map, tp);
+ if (mapf) {
+ (void) fclose(mapf);
+ return 0;
+ }
+
+ return errno;
+}
+#endif /* HAS_FILE_MAPS */
diff --git a/usr.sbin/amd/amd/info_hes.c b/usr.sbin/amd/amd/info_hes.c
new file mode 100644
index 0000000..875cfe7
--- /dev/null
+++ b/usr.sbin/amd/amd/info_hes.c
@@ -0,0 +1,697 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_hes.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_hes.c,v 5.2.2.1 1992/02/09 15:08:29 jsp beta $
+ *
+ */
+
+/*
+ * Get info from Hesiod
+ *
+ * Zone transfer code from Bruce Cole <cole@cs.wisc.edu>
+ */
+
+#include "am.h"
+
+#ifdef HAS_HESIOD_MAPS
+#include <hesiod.h>
+
+#define HES_PREFIX "hesiod."
+#define HES_PREFLEN 7
+
+#ifdef HAS_HESIOD_RELOAD
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <sys/uio.h>
+#include <netdb.h>
+
+/*
+ * Patch up broken system include files
+ */
+#ifndef C_HS
+#define C_HS 4
+#endif
+#ifndef T_TXT
+#define T_TXT 16
+#endif
+
+static int soacnt;
+static struct timeval hs_timeout;
+static int servernum;
+#endif /* HAS_HESIOD_RELOAD */
+
+/*
+ * No easy way to probe the server - check the map name begins with "hesiod."
+ */
+int hesiod_init P((char *map, time_t *tp));
+int hesiod_init(map, tp)
+char *map;
+time_t *tp;
+{
+#ifdef DEBUG
+ dlog("hesiod_init(%s)", map);
+#endif
+ *tp = 0;
+ return strncmp(map, HES_PREFIX, HES_PREFLEN) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Make Hesiod name. Skip past the "hesiod."
+ * at the start of the map name and append
+ * ".automount". The net effect is that a lookup
+ * of /defaults in hesiod.home will result in a
+ * call to hes_resolve("/defaults", "home.automount");
+ */
+#ifdef notdef
+#define MAKE_HES_NAME(dest, src) sprintf(dest, "%s%s", src + HES_PREFLEN, ".automount")
+#endif
+
+/*
+ * Do a Hesiod nameserver call.
+ * Modify time is ignored by Hesiod - XXX
+ */
+int hesiod_search P((mnt_map *m, char *map, char **pval, time_t *tp));
+int hesiod_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ int error;
+ char hes_key[MAXPATHLEN];
+ char **rvec;
+#ifdef DEBUG
+ dlog("hesiod_search(m=%x, map=%s, key=%s, pval=%x tp=%x)", m, map, key, pval, tp);
+#endif
+ /*MAKE_HES_NAME(hes_map, map);*/
+ sprintf(hes_key, "%s.%s", key, map+HES_PREFLEN);
+
+ /*
+ * Call the resolver
+ */
+#ifdef DEBUG
+ dlog("hesiod_search: hes_resolve(%s, %s)", hes_key, "automount");
+#ifdef HAS_HESIOD_RELOAD
+ if (debug_flags & D_FULL)
+ _res.options |= RES_DEBUG;
+#endif
+#endif
+ rvec = hes_resolve(hes_key, "automount");
+ /*
+ * If a reply was forthcoming then return
+ * it (and free subsequent replies)
+ */
+ if (rvec && *rvec) {
+ *pval = *rvec;
+ while (*++rvec)
+ free(*rvec);
+ return 0;
+ }
+
+ /*
+ * Otherwise reflect the hesiod error into a Un*x error
+ */
+#ifdef DEBUG
+ dlog("hesiod_search: Error: %d", hes_error());
+#endif
+ switch (hes_error()) {
+ case HES_ER_NOTFOUND: error = ENOENT; break;
+ case HES_ER_CONFIG: error = EIO; break;
+ case HES_ER_NET: error = ETIMEDOUT; break;
+ default: error = EINVAL; break;
+ }
+#ifdef DEBUG
+ dlog("hesiod_search: Returning: %d", error);
+#endif
+ return error;
+}
+
+#ifdef HAS_HESIOD_RELOAD
+/*
+ * Zone transfer...
+ */
+
+#define MAXHSNS 8
+#define MAX_NSADDR 16
+
+static char *hs_domain;
+static mnt_map *hs_map;
+static int hs_nscount;
+static char nsaddr_list[MAX_NSADDR][sizeof(struct in_addr)];
+
+int hesiod_reload P((mnt_map *m, char *map, void (*fn)()));
+int hesiod_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ char *zone_name, *cp;
+ short domainlen;
+ int status;
+
+#ifdef DEBUG
+ dlog("hesiod_reload (%x %s %x)", m, map, fn);
+#endif DEBUG
+ if (status = res_init()) {
+#ifdef DEBUG
+ dlog("hesiod_reload: res_init failed with %d", status);
+#endif
+ return(status);
+ }
+ _res.retrans = 90;
+ hs_map = m;
+ domainlen = strlen(hostdomain);
+ zone_name = hes_to_bind(map+HES_PREFLEN, "automount");
+ if (*zone_name == '.')
+ zone_name++;
+ hs_domain = zone_name;
+ /* Traverse the DNS tree until we find an SOA we can transfer from.
+ (Our initial zone_name is likely to just be a subtree of a
+ real zone). */
+ do {
+ /* If we can't find any NS records, go up a level in the
+ DNS tree */
+ if (hs_get_ns_list(zone_name) == 0 &&
+ hs_zone_transfer(zone_name) == 0)
+ return(0);
+ /* Move up DNS tree by one component */
+ if (cp = strchr(zone_name, '.'))
+ zone_name = ++cp;
+ else
+ break;
+ } while (strlen(zone_name) >= domainlen);
+#ifdef DEBUG
+ dlog("hesiod_reload: Giving up on %s", hs_domain);
+#endif
+ return(-1);
+}
+
+hs_zone_transfer(domain)
+char *domain;
+{
+ int status, len;
+ char buf[PACKETSZ];
+ /* Want to make sure ansbuf is well alligned */
+ long ansbuf[PACKETSZ/sizeof(long)];
+
+#ifdef DEBUG
+ dlog("hs_zone_transfer (%s)", domain);
+#endif
+ if ((len = res_mkquery(QUERY, domain, C_HS, T_AXFR,
+ (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_zone_transfer: res_mkquery failed");
+#endif
+ errno = 0;
+ return(-1);
+ }
+ if ((status = hs_res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_zone_transfer: hs_res_send failed. status %d errno %d",
+ status, errno);
+#endif
+ errno = 0;
+ return(-1);
+ }
+ return(0);
+}
+
+#define hs_server_addr(ns) ((struct in_addr *) nsaddr_list[ns])
+
+hs_res_send(buf, buflen, answer, anslen)
+char *buf;
+int buflen;
+char *answer;
+int anslen;
+{
+ int retry, ns;
+ u_short id, len;
+ HEADER *hp = (HEADER *) buf;
+ struct iovec iov[2];
+ static int s = -1;
+ int status;
+ struct sockaddr_in server;
+
+ soacnt = 0;
+ id = hp->id;
+ /*
+ * Send request, RETRY times, or until successful
+ */
+ for (retry = _res.retry; retry > 0; retry--) {
+ for (ns = 0; ns < hs_nscount; ns++) {
+ hs_timeout.tv_sec =
+ (_res.retrans << (_res.retry - retry))
+ / hs_nscount;
+ if (hs_timeout.tv_sec <= 0)
+ hs_timeout.tv_sec = 1;
+ hs_timeout.tv_usec = 0;
+ if (s < 0) {
+ s = socket(AF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ continue;
+ }
+ servernum = ns;
+ bcopy(hs_server_addr(ns), &server.sin_addr,
+ sizeof(struct in_addr));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(NAMESERVER_PORT);
+
+ if (connect(s, &server,
+ sizeof(struct sockaddr)) < 0) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ /*
+ * Send length & message
+ */
+ len = htons((u_short)buflen);
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = sizeof(len);
+ iov[1].iov_base = buf;
+ iov[1].iov_len = buflen;
+ if (writev(s, iov, 2) != sizeof(len) + buflen) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ status = 0;
+ while (s != -1 && soacnt < 2 && status != -2) {
+ if ((status =
+ hs_readresp(s, answer, anslen)) == -1) {
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ if (status == -2) {
+ /* There was a permanent error transfering this
+ zone. Give up. */
+ if (s != -1) {
+ (void) close(s);
+ s = -1;
+ }
+ return(-1);
+ }
+ if (s == -1)
+ continue;
+ return (0);
+ }
+ }
+ if (errno == 0)
+ errno = ETIMEDOUT;
+ return (-1);
+}
+
+/* Returns:
+ 0: Success
+ -1: Error
+ -2: Permanent failure
+*/
+hs_readresp(s, answer, anslen)
+int s;
+char *answer;
+int anslen;
+{
+ register int len, n;
+ char *cp;
+
+ cp = answer;
+ len = sizeof(short);
+ while (len != 0 &&
+ (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0)
+ return(-1);
+ cp = answer;
+ if ((len = _getshort(cp)) > anslen) {
+#ifdef DEBUG
+ dlog("hs_readresp: response too long: %d", len);
+#endif
+ return(-1);
+ }
+ while (len != 0 &&
+ (n = hs_res_vcread(s, (char *)cp, (int)len, &hs_timeout)) > 0) {
+ cp += n;
+ len -= n;
+ }
+ if (n <= 0)
+ return(-1);
+ return(hs_parse(answer, answer+PACKETSZ));
+}
+
+hs_res_vcread(sock, buf, buflen, timeout)
+int sock, buflen;
+char *buf;
+struct timeval *timeout;
+{
+ register int n;
+
+ if ((n = hs_res_selwait(sock, timeout)) > 0)
+ return(read(sock, buf, buflen));
+ else
+ return(n);
+}
+
+hs_res_selwait(sock, timeout)
+int sock;
+struct timeval *timeout;
+{
+ fd_set dsmask;
+ register int n;
+
+ /*
+ * Wait for reply
+ */
+ FD_ZERO(&dsmask);
+ FD_SET(sock, &dsmask);
+ n = select(sock+1, &dsmask, (fd_set *)NULL,
+ (fd_set *)NULL, timeout);
+ return(n);
+}
+
+/* Returns:
+ 0: Success
+ -1: Error
+ -2: Permanent failure
+*/
+hs_parse(msg, eom)
+char *msg, *eom;
+{
+ register char *cp;
+ register HEADER *hp;
+ register int n, len;
+ int qdcount, ancount;
+ char key[PACKETSZ];
+ char *key_cpy, *value, *hs_make_value();
+ short type;
+
+ hp = (HEADER *)msg;
+ if (hp->rcode != NOERROR || hp->opcode != QUERY) {
+ char dq[20];
+#ifdef DEBUG
+ dlog("Bad response (%d) from nameserver %s", hp->rcode, inet_dquad(dq, hs_server_addr(servernum)->s_addr));
+#endif DEBUG
+ return(-1);
+ }
+ cp = msg + sizeof(HEADER);
+ ancount = ntohs(hp->ancount);
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0)
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ if (soacnt == 0 && ancount == 0) {
+ /* XXX We should look for NS records to find SOA */
+#ifdef DEBUG
+ dlog("No SOA found");
+#endif
+ return(-2);
+ }
+ while (ancount-- > 0 && cp < eom) {
+ if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0)
+ break;
+ cp += n;
+ if ((type = _getshort(cp)) == T_SOA) {
+ soacnt++;
+ }
+ cp += 2*sizeof(u_short) + sizeof(u_long);
+ len = _getshort(cp);
+ cp += sizeof(u_short);
+ /* Check to see if key is in our domain */
+ if (type == T_TXT && hs_strip_our_domain(key)) {
+ value = hs_make_value(cp, len);
+ if (value == NULL)
+ return(-1);
+ key_cpy = strdup(key);
+#ifdef DEBUG
+ dlog("hs_parse: Parsed key: %s, value: %s", key,
+ value);
+#endif
+ mapc_add_kv(hs_map, key_cpy, value);
+ }
+ cp += len;
+ errno = 0;
+ }
+ return(0);
+}
+
+/* Check to see if the domain name in the supplied argument matches
+ hs_domain. Strip hs_domain from supplied argument if so. */
+hs_strip_our_domain(name)
+char *name;
+{
+ char *end_pos;
+ short targ_len, cur_len;
+
+ targ_len = strlen(hs_domain);
+ cur_len = strlen(name);
+ if (cur_len <= targ_len)
+ return(0);
+ end_pos = &name[cur_len - targ_len];
+ if (strcmp(end_pos, hs_domain) != 0)
+ return(0);
+ if (*--end_pos != '.')
+ return(0);
+ *end_pos = '\0';
+ return(1);
+}
+
+#define MAXDATA 8*1024
+
+char *
+hs_make_value(cp, len)
+char *cp;
+int len;
+{
+ char *value, *cpcpy, *valuep;
+ int cnt, nextcnt, totalcnt, lencpy;
+#ifdef DEBUG
+ char *dbgname;
+
+ dbgname = &cp[1];
+#endif DEBUG
+
+ lencpy = len;
+ cpcpy = cp;
+ totalcnt = 0;
+ cnt = *cpcpy++;
+ while (cnt) {
+ totalcnt += cnt;
+ lencpy -= cnt+1;
+ if (lencpy == 0)
+ break;
+ nextcnt = cpcpy[cnt];
+ cpcpy = &cpcpy[cnt+1];
+ cnt = nextcnt;
+ }
+ if (totalcnt < 1 || totalcnt > MAXDATA || totalcnt > len) {
+#ifdef DEBUG
+ dlog("TXT RR not of expected length (%d %d): %s", totalcnt,
+ len, dbgname);
+#endif DEBUG
+ return(NULL);
+ }
+ /* Allocate null terminated string */
+ value = (char *) xmalloc(totalcnt+1);
+ value[totalcnt] = '\0';
+ cnt = *cp++;
+ valuep = value;
+ while (cnt) {
+ bcopy(cp, valuep, cnt);
+ len -= cnt+1;
+ if (len == 0)
+ break;
+ valuep = &valuep[cnt];
+ nextcnt = cp[cnt];
+ cp = &cp[cnt+1];
+ cnt = nextcnt;
+ }
+ return(value);
+}
+
+hs_make_ns_query(domain, ansbuf)
+char *domain;
+char *ansbuf;
+{
+ int status, len;
+ char buf[PACKETSZ];
+
+ if ((len = res_mkquery(QUERY, domain, C_HS, T_NS,
+ (char *)NULL, 0, NULL, buf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: res_mkquery failed");
+#endif
+ errno = 0;
+ return(-1);
+ }
+ if ((status = res_send(buf, len, (char *)ansbuf, PACKETSZ)) == -1) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: res_send failed. status %d errno %d",
+ status, errno);
+#endif
+ errno = 0;
+ return(-1);
+ }
+ return(0);
+}
+
+static void
+add_address(addr)
+struct in_addr *addr;
+{
+ char dq[20];
+ bcopy((char *)addr, nsaddr_list[hs_nscount++], sizeof(struct in_addr));
+#ifdef DEBUG
+ dlog("Adding NS address %s", inet_dquad(dq, addr->s_addr));
+#endif DEBUG
+}
+
+hs_get_ns_list(domain)
+char *domain;
+{
+ register HEADER *hp;
+ int qdcount, nscount;
+ register char *cp;
+ register int n, len;
+ char key[PACKETSZ], name[PACKETSZ], msg[PACKETSZ], *eom;
+ register long **hptr;
+ struct hostent *ghp;
+ int numns;
+ char nsname[MAXHSNS][MAXDATA];
+ int nshaveaddr[MAXHSNS], i;
+ short type;
+
+ if (hs_make_ns_query(domain, msg) == -1)
+ return(-1);
+ numns = hs_nscount = 0;
+ eom = &msg[PACKETSZ];
+ bzero(nsname, sizeof(nsname));
+ hp = (HEADER *)msg;
+ if (hp->rcode != NOERROR || hp->opcode != QUERY) {
+#ifdef DEBUG
+ dlog("Bad response (%d) from nameserver %#x", hp->rcode,
+ hs_server_addr(servernum)->s_addr);
+#endif DEBUG
+ return(-1);
+ }
+ cp = msg + sizeof(HEADER);
+ qdcount = ntohs(hp->qdcount);
+ while (qdcount-- > 0)
+ cp += dn_skipname(cp, eom) + QFIXEDSZ;
+ nscount = ntohs(hp->ancount) + ntohs(hp->nscount) + ntohs(hp->arcount);
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Processing %d response records", nscount);
+#endif
+ for (;nscount; nscount--) {
+ if ((n = dn_expand(msg, eom, cp, key, PACKETSZ)) < 0)
+ break;
+ cp += n;
+ type = _getshort(cp);
+ cp += 2*sizeof(u_short) + sizeof(u_long);
+ len = _getshort(cp);
+ cp += sizeof(u_short);
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Record type: %d", type);
+#endif
+ switch (type) {
+ case T_NS:
+ if (numns >= MAXHSNS || strcasecmp(domain, key) != 0)
+ break;
+ if ((n = dn_expand(msg, eom, cp, name, PACKETSZ)) < 0)
+ break;
+#ifdef DEBUG
+ dlog("hs_get_ns_list: NS name: %s", name);
+#endif
+ for (i = 0; i < numns; i++)
+ if (strcasecmp(nsname[i], name) == 0)
+ break;
+ if (i == numns) {
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Saving name %s", name);
+#endif
+ strncpy(nsname[numns], name, MAXDATA);
+ nshaveaddr[numns] = 0;
+ numns++;
+ }
+ break;
+ case T_A:
+ if (hs_nscount == MAX_NSADDR)
+ break;
+ for (i = 0; i < numns; i++) {
+ if (strcasecmp(nsname[i], domain) == 0) {
+ nshaveaddr[i]++;
+ add_address((struct in_addr *) cp);
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if (hs_nscount == MAX_NSADDR)
+ break;
+ cp += len;
+ errno = 0;
+ }
+#ifdef DEBUG
+ dlog("hs_get_ns_list: Found %d NS records", numns);
+#endif
+ for (i = 0; i < numns; i++) {
+ if (nshaveaddr[i])
+ continue;
+ if ((ghp = gethostbyname(nsname[i])) == 0)
+ continue;
+ for (hptr = (long **)ghp->h_addr_list;
+ *hptr && hs_nscount < MAX_NSADDR; hptr++) {
+ add_address((struct in_addr *) *hptr);
+ }
+ }
+ if (hs_nscount)
+ return(0);
+#ifdef DEBUG
+ dlog("No NS records found for %s", domain);
+ return(-1);
+#endif DEBUG
+}
+#endif /* HAS_HESIOD_RELOAD */
+#endif /* HAS_HESIOD_MAPS */
diff --git a/usr.sbin/amd/amd/info_ndbm.c b/usr.sbin/amd/amd/info_ndbm.c
new file mode 100644
index 0000000..d3deaa1
--- /dev/null
+++ b/usr.sbin/amd/amd/info_ndbm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_ndbm.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_ndbm.c,v 5.2.2.1 1992/02/09 15:08:31 jsp beta $
+ *
+ */
+
+/*
+ * Get info from NDBM map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NDBM_MAPS
+
+#include <ndbm.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+static int search_ndbm P((DBM *db, char *key, char **val));
+static int search_ndbm(db, key, val)
+DBM *db;
+char *key;
+char **val;
+{
+ datum k, v;
+ k.dptr = key;
+ k.dsize = strlen(key) + 1;
+ v = dbm_fetch(db, k);
+ if (v.dptr) {
+ *val = strdup(v.dptr);
+ return 0;
+ }
+ return ENOENT;
+}
+
+int ndbm_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int ndbm_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ DBM *db;
+
+ db = dbm_open(map, O_RDONLY, 0);
+ if (db) {
+ struct stat stb;
+ int error;
+ error = fstat(dbm_pagfno(db), &stb);
+ if (!error && *tp < stb.st_mtime) {
+ *tp = stb.st_mtime;
+ error = -1;
+ } else {
+ error = search_ndbm(db, key, pval);
+ }
+ (void) dbm_close(db);
+ return error;
+ }
+
+ return errno;
+}
+
+int ndbm_init P((char *map, time_t *tp));
+int ndbm_init(map, tp)
+char *map;
+time_t *tp;
+{
+ DBM *db;
+
+ db = dbm_open(map, O_RDONLY, 0);
+ if (db) {
+ struct stat stb;
+
+ if (fstat(dbm_pagfno(db), &stb) < 0)
+ *tp = clocktime();
+ else
+ *tp = stb.st_mtime;
+ dbm_close(db);
+ return 0;
+ }
+
+ return errno;
+}
+
+#endif /* HAS_NDBM_MAPS */
diff --git a/usr.sbin/amd/amd/info_nis.c b/usr.sbin/amd/amd/info_nis.c
new file mode 100644
index 0000000..ac80f5f
--- /dev/null
+++ b/usr.sbin/amd/amd/info_nis.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_nis.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_nis.c,v 5.2.2.1 1992/02/09 15:08:32 jsp beta $
+ *
+ */
+
+/*
+ * Get info from NIS map
+ */
+
+#include "am.h"
+
+#ifdef HAS_NIS_MAPS
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+/*
+ * Figure out the nis domain name
+ */
+static int determine_nis_domain(P_void)
+{
+static int nis_not_running = 0;
+
+ char default_domain[YPMAXDOMAIN];
+
+ if (nis_not_running)
+ return ENOENT;
+
+ if (getdomainname(default_domain, sizeof(default_domain)) < 0) {
+ nis_not_running = 1;
+ plog(XLOG_ERROR, "getdomainname: %m");
+ return EIO;
+ }
+
+ if (!*default_domain) {
+ nis_not_running = 1;
+ plog(XLOG_WARNING, "NIS domain name is not set. NIS ignored.");
+ return ENOENT;
+ }
+
+ domain = strdup(default_domain);
+
+ return 0;
+}
+
+
+#ifdef HAS_NIS_RELOAD
+struct nis_callback_data {
+ mnt_map *ncd_m;
+ char *ncd_map;
+ void (*ncd_fn)();
+};
+
+/*
+ * Callback from yp_all
+ */
+static int callback(status, key, kl, val, vl, data)
+int status;
+char *key;
+int kl;
+char *val;
+int vl;
+struct nis_callback_data *data;
+{
+ if (status == YP_TRUE) {
+ /*
+ * Add to list of maps
+ */
+ char *kp = strnsave(key, kl);
+ char *vp = strnsave(val, vl);
+ (*data->ncd_fn)(data->ncd_m, kp, vp);
+
+ /*
+ * We want more ...
+ */
+ return FALSE;
+ } else {
+ /*
+ * NOMORE means end of map - otherwise log error
+ */
+ if (status != YP_NOMORE) {
+ /*
+ * Check what went wrong
+ */
+ int e = ypprot_err(status);
+
+#ifdef DEBUG
+ plog(XLOG_ERROR, "yp enumeration of %s: %s, status=%d, e=%d",
+ data->ncd_map, yperr_string(e), status, e);
+#else
+ plog(XLOG_ERROR, "yp enumeration of %s: %s", data->ncd_map, yperr_string(e));
+#endif
+ }
+
+ return TRUE;
+ }
+}
+
+int nis_reload P((mnt_map *m, char *map, void (*fn)()));
+int nis_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ struct ypall_callback cbinfo;
+ int error;
+ struct nis_callback_data data;
+
+ if (!domain) {
+ error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ data.ncd_m = m;
+ data.ncd_map = map;
+ data.ncd_fn = fn;
+ cbinfo.data = (voidp) &data;
+ cbinfo.foreach = callback;
+
+ error = yp_all(domain, map, &cbinfo);
+
+ if (error)
+ plog(XLOG_ERROR, "error grabbing nis map of %s: %s", map, yperr_string(ypprot_err(error)));
+
+ return error;
+}
+#endif /* HAS_NIS_RELOAD */
+
+/*
+ * Try to locate a key using NIS.
+ */
+int nis_search P((mnt_map *m, char *map, char *key, char **val, time_t *tp));
+int nis_search(m, map, key, val, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **val;
+time_t *tp;
+{
+ int outlen;
+ int res;
+ int order;
+
+ /*
+ * Make sure domain initialised
+ */
+ if (!domain) {
+ int error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ /*
+ * Check if map has changed
+ */
+ if (yp_order(domain, map, &order))
+ return EIO;
+ if ((time_t) order > *tp) {
+ *tp = (time_t) order;
+ return -1;
+ }
+
+ /*
+ * Lookup key
+ */
+ res = yp_match(domain, map, key, strlen(key), val, &outlen);
+
+ /*
+ * Do something interesting with the return code
+ */
+ switch (res) {
+ case 0:
+ return 0;
+
+ case YPERR_KEY:
+ return ENOENT;
+
+ default:
+ plog(XLOG_ERROR, "%s: %s", map, yperr_string(res));
+ return EIO;
+ }
+}
+
+int nis_init P((char *map, time_t *tp));
+int nis_init(map, tp)
+char *map;
+time_t *tp;
+{
+ int order;
+
+ if (!domain) {
+ int error = determine_nis_domain();
+ if (error)
+ return error;
+ }
+
+ /*
+ * To see if the map exists, try to find
+ * a master for it.
+ */
+ if (yp_order(domain, map, &order))
+ return ENOENT;
+ *tp = (time_t) order;
+#ifdef DEBUG
+ dlog("NIS master for %s@%s has order %d", map, domain, order);
+#endif
+ return 0;
+}
+#endif /* HAS_NIS_MAPS */
diff --git a/usr.sbin/amd/amd/info_passwd.c b/usr.sbin/amd/amd/info_passwd.c
new file mode 100644
index 0000000..3123e38
--- /dev/null
+++ b/usr.sbin/amd/amd/info_passwd.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_passwd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_passwd.c,v 5.2.2.1 1992/02/09 15:08:33 jsp beta $
+ *
+ */
+
+/*
+ * Get info from password "file"
+ *
+ * This is experimental and probably doesn't
+ * do what you expect.
+ */
+
+#include "am.h"
+
+#ifdef HAS_PASSWD_MAPS
+#include <pwd.h>
+
+#define PASSWD_MAP "/etc/passwd"
+
+/*
+ * Nothing to probe - check the map name is PASSWD_MAP.
+ */
+int passwd_init P((char *map, time_t *tp));
+int passwd_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return strcmp(map, PASSWD_MAP) == 0 ? 0 : ENOENT;
+}
+
+
+/*
+ * Grab the entry via the getpwname routine
+ * Modify time is ignored by passwd - XXX
+ */
+int passwd_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int passwd_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ char *dir = 0;
+ struct passwd *pw;
+ if (strcmp(key, "/defaults") == 0) {
+ *pval = strdup("type:=nfs");
+ return 0;
+ }
+
+ pw = getpwnam(key);
+ if (pw) {
+ /*
+ * We chop the home directory up as follows:
+ * /anydir/dom1/dom2/dom3/user
+ *
+ * and return
+ * rfs:=/anydir/dom3;rhost:=dom3.dom2.dom1;sublink:=user
+ *
+ * This allows cross-domain entries in your passwd file.
+ * ... but forget about security!
+ */
+ char *user;
+ char *p, *q;
+ char val[MAXPATHLEN];
+ char rhost[MAXHOSTNAMELEN];
+ dir = strdup(pw->pw_dir);
+ /*
+ * Find user name. If no / then Invalid...
+ */
+ user = strrchr(dir, '/');
+ if (!user)
+ goto enoent;
+ *user++ = '\0';
+ /*
+ * Find start of host "path". If no / then Invalid...
+ */
+ p = strchr(dir+1, '/');
+ if (!p)
+ goto enoent;
+ *p++ = '\0';
+ /*
+ * At this point, p is dom1/dom2/dom3
+ * Copy, backwards, into rhost replacing
+ * / with .
+ */
+ rhost[0] = '\0';
+ do {
+ q = strrchr(p, '/');
+ if (q) {
+ strcat(rhost, q + 1);
+ strcat(rhost, ".");
+ *q = '\0';
+ } else {
+ strcat(rhost, p);
+ }
+ } while (q);
+ /*
+ * Sanity check
+ */
+ if (*rhost == '\0' || *user == '\0' || *dir == '\0')
+ goto enoent;
+ /*
+ * Make up return string
+ */
+ q = strchr(rhost, '.');
+ if (q)
+ *q = '\0';
+ sprintf(val, "rfs:=%s/%s;rhost:=%s;sublink:=%s;fs:=${autodir}%s",
+ dir, rhost, rhost, user, pw->pw_dir);
+ if (q)
+ *q = '.';
+ *pval = strdup(val);
+ return 0;
+ }
+
+enoent:
+ if (dir)
+ free(dir);
+
+ return ENOENT;
+}
+#endif /* HAS_PASSWD_MAPS */
diff --git a/usr.sbin/amd/amd/info_union.c b/usr.sbin/amd/amd/info_union.c
new file mode 100644
index 0000000..e3062ad
--- /dev/null
+++ b/usr.sbin/amd/amd/info_union.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)info_union.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: info_union.c,v 5.2.2.1 1992/02/09 15:08:34 jsp beta $
+ *
+ */
+
+/*
+ * Get info from the system namespace
+ *
+ * NOTE: Cannot handle reads back through the automounter.
+ * THIS WILL CAUSE A DEADLOCK!
+ */
+
+#include "am.h"
+
+#ifdef HAS_UNION_MAPS
+
+#ifdef _POSIX_SOURCE
+#include <dirent.h>
+#define DIRENT struct dirent
+#else
+#include <sys/dir.h>
+#define DIRENT struct direct
+#endif
+
+#define UNION_PREFIX "union:"
+#define UNION_PREFLEN 6
+
+/*
+ * No way to probe - check the map name begins with "union:"
+ */
+int union_init P((char *map, time_t *tp));
+int union_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return strncmp(map, UNION_PREFIX, UNION_PREFLEN) == 0 ? 0 : ENOENT;
+}
+
+int union_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+int union_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ char *mapd = strdup(map + UNION_PREFLEN);
+ char **v = strsplit(mapd, ':', '\"');
+ char **p;
+ for (p = v; p[1]; p++)
+ ;
+ *pval = xmalloc(strlen(*p) + 5);
+ sprintf(*pval, "fs:=%s", *p);
+ free(mapd);
+ free(v);
+ return 0;
+}
+
+int union_reload P((mnt_map *m, char *map, void (*fn)()));
+int union_reload(m, map, fn)
+mnt_map *m;
+char *map;
+void (*fn)();
+{
+ char *mapd = strdup(map + UNION_PREFLEN);
+ char **v = strsplit(mapd, ':', '\"');
+ char **dir;
+
+ /*
+ * Add fake /defaults entry
+ */
+ (*fn)(m, strdup("/defaults"), strdup("type:=link;opts:=nounmount;sublink:=${key}"));
+
+ for (dir = v; *dir; dir++) {
+ int dlen;
+ DIRENT *dp;
+ DIR *dirp = opendir(*dir);
+ if (!dirp) {
+ plog(XLOG_USER, "Cannot read directory %s: %m", *dir);
+ continue;
+ }
+ dlen = strlen(*dir);
+#ifdef DEBUG
+ dlog("Reading directory %s...", *dir);
+#endif
+ while (dp = readdir(dirp)) {
+ char *val;
+ if (dp->d_name[0] == '.' &&
+ (dp->d_name[1] == '\0' ||
+ (dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
+ continue;
+
+#ifdef DEBUG
+ dlog("... gives %s", dp->d_name);
+#endif
+ val = xmalloc(dlen + 5);
+ sprintf(val, "fs:=%s", *dir);
+ (*fn)(m, strdup(dp->d_name), val);
+ }
+ closedir(dirp);
+ }
+ /*
+ * Add wildcard entry
+ */
+ { char *val = xmalloc(strlen(dir[-1]) + 5);
+ sprintf(val, "fs:=%s", dir[-1]);
+ (*fn)(m, strdup("*"), val);
+ }
+ free(mapd);
+ free(v);
+ return 0;
+}
+
+#endif /* HAS_UNION_MAPS */
diff --git a/usr.sbin/amd/amd/map.c b/usr.sbin/amd/amd/map.c
new file mode 100644
index 0000000..6f2acb3
--- /dev/null
+++ b/usr.sbin/amd/amd/map.c
@@ -0,0 +1,1140 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: map.c,v 5.2.2.1 1992/02/09 15:08:36 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)map.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+
+/*
+ * Generation Numbers.
+ *
+ * Generation numbers are allocated to every node created
+ * by amd. When a filehandle is computed and sent to the
+ * kernel, the generation number makes sure that it is safe
+ * to reallocate a node slot even when the kernel has a cached
+ * reference to its old incarnation.
+ * No garbage collection is done, since it is assumed that
+ * there is no way that 2^32 generation numbers could ever
+ * be allocated by a single run of amd - there is simply
+ * not enough cpu time available.
+ */
+static unsigned int am_gen = 2; /* Initial generation number */
+#define new_gen() (am_gen++)
+
+am_node **exported_ap = (am_node **) 0;
+int exported_ap_size = 0;
+int first_free_map = 0; /* First available free slot */
+int last_used_map = -1; /* Last unavailable used slot */
+static int timeout_mp_id; /* Id from last call to timeout */
+
+/*
+ * This is the default attributes field which
+ * is copied into every new node to be created.
+ * The individual filesystem fs_init() routines
+ * patch the copy to represent the particular
+ * details for the relevant filesystem type
+ */
+static struct fattr gen_fattr = {
+ NFLNK, /* type */
+ NFSMODE_LNK | 0777, /* mode */
+ 1, /* nlink */
+ 0, /* uid */
+ 0, /* gid */
+ 0, /* size */
+ 4096, /* blocksize */
+ 0, /* rdev */
+ 1, /* blocks */
+ 0, /* fsid */
+ 0, /* fileid */
+ { 0, 0 }, /* atime */
+ { 0, 0 }, /* mtime */
+ { 0, 0 }, /* ctime */
+};
+
+/*
+ * Resize exported_ap map
+ */
+static int exported_ap_realloc_map P((int nsize));
+static int exported_ap_realloc_map(nsize)
+int nsize;
+{
+#ifdef notdef
+ /*
+ * If a second realloc occasionally causes Amd to die
+ * in then include this check.
+ */
+ if (exported_ap_size != 0) /* XXX */
+ return 0;
+#endif
+
+ /*
+ * this shouldn't happen, but...
+ */
+ if (nsize < 0 || nsize == exported_ap_size)
+ return 0;
+
+ exported_ap = (am_node **) xrealloc((voidp) exported_ap, nsize * sizeof(am_node*));
+
+ if (nsize > exported_ap_size)
+ bzero((char*) (exported_ap+exported_ap_size),
+ (nsize - exported_ap_size) * sizeof(am_node*));
+ exported_ap_size = nsize;
+
+ return 1;
+}
+
+
+/*
+ * The root of the mount tree.
+ */
+am_node *root_node;
+
+/*
+ * Allocate a new mount slot and create
+ * a new node.
+ * Fills in the map number of the node,
+ * but leaves everything else uninitialised.
+ */
+am_node *exported_ap_alloc(P_void)
+{
+ am_node *mp, **mpp;
+
+ /*
+ * First check if there are any slots left, realloc if needed
+ */
+ if (first_free_map >= exported_ap_size)
+ if (!exported_ap_realloc_map(exported_ap_size + NEXP_AP))
+ return 0;
+
+ /*
+ * Grab the next free slot
+ */
+ mpp = exported_ap + first_free_map;
+ mp = *mpp = ALLOC(am_node);
+ bzero((char *) mp, sizeof(*mp));
+
+ mp->am_mapno = first_free_map++;
+
+ /*
+ * Update free pointer
+ */
+ while (first_free_map < exported_ap_size && exported_ap[first_free_map])
+ first_free_map++;
+
+ if (first_free_map > last_used_map)
+ last_used_map = first_free_map - 1;
+
+ /*
+ * Shrink exported_ap if reasonable
+ */
+ if (last_used_map < exported_ap_size - (NEXP_AP + NEXP_AP_MARGIN))
+ exported_ap_realloc_map(exported_ap_size - NEXP_AP);
+
+#ifdef DEBUG
+ /*dlog("alloc_exp: last_used_map = %d, first_free_map = %d\n",
+ last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+ return mp;
+}
+
+/*
+ * Free a mount slot
+ */
+void exported_ap_free P((am_node *mp));
+void exported_ap_free(mp)
+am_node *mp;
+{
+ /*
+ * Sanity check
+ */
+ if (!mp)
+ return;
+
+ /*
+ * Zero the slot pointer to avoid double free's
+ */
+ exported_ap[mp->am_mapno] = 0;
+
+ /*
+ * Update the free and last_used indices
+ */
+ if (mp->am_mapno == last_used_map)
+ while (last_used_map >= 0 && exported_ap[last_used_map] == 0)
+ --last_used_map;
+
+ if (first_free_map > mp->am_mapno)
+ first_free_map = mp->am_mapno;
+
+#ifdef DEBUG
+ /*dlog("free_exp: last_used_map = %d, first_free_map = %d\n",
+ last_used_map, first_free_map);*/
+#endif /* DEBUG */
+
+ /*
+ * Free the mount node
+ */
+ free((voidp) mp);
+}
+
+/*
+ * Insert mp into the correct place,
+ * where p_mp is its parent node.
+ * A new node gets placed as the youngest sibling
+ * of any other children, and the parent's child
+ * pointer is adjusted to point to the new child node.
+ */
+void insert_am(mp, p_mp)
+am_node *mp;
+am_node *p_mp;
+{
+ /*
+ * If this is going in at the root then flag it
+ * so that it cannot be unmounted by amq.
+ */
+ if (p_mp == root_node)
+ mp->am_flags |= AMF_ROOT;
+ /*
+ * Fill in n-way links
+ */
+ mp->am_parent = p_mp;
+ mp->am_osib = p_mp->am_child;
+ if (mp->am_osib)
+ mp->am_osib->am_ysib = mp;
+ p_mp->am_child = mp;
+}
+
+/*
+ * Remove am from its place in the mount tree
+ */
+void remove_am(mp)
+am_node *mp;
+{
+ /*
+ * 1. Consistency check
+ */
+ if (mp->am_child && mp->am_parent) {
+ plog(XLOG_WARNING, "children of \"%s\" still exist - deleting anyway", mp->am_path);
+ }
+
+ /*
+ * 2. Update parent's child pointer
+ */
+ if (mp->am_parent && mp->am_parent->am_child == mp)
+ mp->am_parent->am_child = mp->am_osib;
+
+ /*
+ * 3. Unlink from sibling chain
+ */
+ if (mp->am_ysib)
+ mp->am_ysib->am_osib = mp->am_osib;
+ if (mp->am_osib)
+ mp->am_osib->am_ysib = mp->am_ysib;
+}
+
+/*
+ * Compute a new time to live value for a node.
+ */
+void new_ttl(mp)
+am_node *mp;
+{
+ mp->am_timeo_w = 0;
+
+ mp->am_ttl = clocktime();
+ mp->am_fattr.atime.seconds = mp->am_ttl;
+ mp->am_ttl += mp->am_timeo; /* sun's -tl option */
+}
+
+void mk_fattr P((am_node *mp, ftype vntype));
+void mk_fattr(mp, vntype)
+am_node *mp;
+ftype vntype;
+{
+ switch (vntype) {
+ case NFDIR:
+ mp->am_fattr.type = NFDIR;
+ mp->am_fattr.mode = NFSMODE_DIR | 0555;
+ mp->am_fattr.nlink = 2;
+ mp->am_fattr.size = 512;
+ break;
+ case NFLNK:
+ mp->am_fattr.type = NFLNK;
+ mp->am_fattr.mode = NFSMODE_LNK | 0777;
+ mp->am_fattr.nlink = 1;
+ mp->am_fattr.size = 0;
+ break;
+ default:
+ plog(XLOG_FATAL, "Unknown fattr type %d - ignored", vntype);
+ break;
+ }
+}
+
+/*
+ * Initialise an allocated mount node.
+ * It is assumed that the mount node was bzero'd
+ * before getting here so anything that would
+ * be set to zero isn't done here.
+ */
+void init_map(mp, dir)
+am_node *mp;
+char *dir;
+{
+ /* mp->am_mapno initalised by exported_ap_alloc */
+ mp->am_mnt = new_mntfs();
+ mp->am_name = strdup(dir);
+ mp->am_path = strdup(dir);
+ /*mp->am_link = 0;*/
+ /*mp->am_parent = 0;*/
+ /*mp->am_ysib = 0;*/
+ /*mp->am_osib = 0;*/
+ /*mp->am_child = 0;*/
+ /*mp->am_flags = 0;*/
+ /*mp->am_error = 0;*/
+ mp->am_gen = new_gen();
+ /*mp->am_pref = 0;*/
+
+ mp->am_timeo = am_timeo;
+ mp->am_attr.status = NFS_OK;
+ mp->am_fattr = gen_fattr;
+ mp->am_fattr.fsid = 42;
+ mp->am_fattr.fileid = 0;
+ mp->am_fattr.atime.seconds = clocktime();
+ mp->am_fattr.atime.useconds = 0;
+ mp->am_fattr.mtime = mp->am_fattr.ctime = mp->am_fattr.atime;
+
+ new_ttl(mp);
+ mp->am_stats.s_mtime = mp->am_fattr.atime.seconds;
+ /*mp->am_private = 0;*/
+}
+
+/*
+ * Free a mount node.
+ * The node must be already unmounted.
+ */
+void free_map(mp)
+am_node *mp;
+{
+ remove_am(mp);
+
+ if (mp->am_link)
+ free(mp->am_link);
+ if (mp->am_name)
+ free(mp->am_name);
+ if (mp->am_path)
+ free(mp->am_path);
+ if (mp->am_pref)
+ free(mp->am_pref);
+
+ if (mp->am_mnt)
+ free_mntfs(mp->am_mnt);
+
+ exported_ap_free(mp);
+}
+
+/*
+ * Convert from file handle to
+ * automount node.
+ */
+am_node *fh_to_mp3(fhp, rp, c_or_d)
+nfs_fh *fhp;
+int *rp;
+int c_or_d;
+{
+ struct am_fh *fp = (struct am_fh *) fhp;
+ am_node *ap = 0;
+
+ /*
+ * Check process id matches
+ * If it doesn't then it is probably
+ * from an old kernel cached filehandle
+ * which is now out of date.
+ */
+ if (fp->fhh_pid != mypid)
+ goto drop;
+
+ /*
+ * Make sure the index is valid before
+ * exported_ap is referenced.
+ */
+ if (fp->fhh_id < 0 || fp->fhh_id >= exported_ap_size)
+ goto drop;
+
+ /*
+ * Get hold of the supposed mount node
+ */
+ ap = exported_ap[fp->fhh_id];
+
+ /*
+ * If it exists then maybe...
+ */
+ if (ap) {
+ /*
+ * Check the generation number in the node
+ * matches the one from the kernel. If not
+ * then the old node has been timed out and
+ * a new one allocated.
+ */
+ if (ap->am_gen != fp->fhh_gen) {
+ ap = 0;
+ goto drop;
+ }
+
+ /*
+ * If the node is hung then locate a new node
+ * for it. This implements the replicated filesystem
+ * retries.
+ */
+ if (ap->am_mnt && FSRV_ISDOWN(ap->am_mnt->mf_server) && ap->am_parent) {
+ int error;
+ am_node *orig_ap = ap;
+#ifdef DEBUG
+ dlog("fh_to_mp3: %s (%s) is hung:- call lookup",
+ orig_ap->am_path, orig_ap->am_mnt->mf_info);
+#endif /* DEBUG */
+ /*
+ * Update modify time of parent node.
+ * With any luck the kernel will re-stat
+ * the child node and get new information.
+ */
+ orig_ap->am_fattr.mtime.seconds = clocktime();
+
+ /*
+ * Call the parent's lookup routine for an object
+ * with the same name. This may return -1 in error
+ * if a mount is in progress. In any case, if no
+ * mount node is returned the error code is propagated
+ * to the caller.
+ */
+ if (c_or_d == VLOOK_CREATE) {
+ ap = (*orig_ap->am_parent->am_mnt->mf_ops->lookuppn)(orig_ap->am_parent,
+ orig_ap->am_name, &error, c_or_d);
+ } else {
+ ap = 0;
+ error = ESTALE;
+ }
+ if (ap == 0) {
+ if (error < 0 && amd_state == Finishing)
+ error = ENOENT;
+ *rp = error;
+ return 0;
+ }
+ /*
+ * Update last access to original node. This
+ * avoids timing it out and so sending ESTALE
+ * back to the kernel.
+ * XXX - Not sure we need this anymore (jsp, 90/10/6).
+ */
+ new_ttl(orig_ap);
+
+ }
+ /*
+ * Disallow references to objects being unmounted, unless
+ * they are automount points.
+ */
+ if (ap->am_mnt && (ap->am_mnt->mf_flags & MFF_UNMOUNTING) &&
+ !(ap->am_flags & AMF_ROOT)) {
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = -1;
+ return 0;
+ }
+ new_ttl(ap);
+ }
+
+drop:
+ if (!ap || !ap->am_mnt) {
+ /*
+ * If we are shutting down then it is likely
+ * that this node has disappeared because of
+ * a fast timeout. To avoid things thrashing
+ * just pretend it doesn't exist at all. If
+ * ESTALE is returned, some NFS clients just
+ * keep retrying (stupid or what - if it's
+ * stale now, what's it going to be in 5 minutes?)
+ */
+ if (amd_state == Finishing)
+ *rp = ENOENT;
+ else
+ *rp = ESTALE;
+ amd_stats.d_stale++;
+ }
+
+ return ap;
+}
+
+am_node *fh_to_mp(fhp)
+nfs_fh *fhp;
+{
+ int dummy;
+ return fh_to_mp2(fhp, &dummy);
+}
+
+/*
+ * Convert from automount node to
+ * file handle.
+ */
+void mp_to_fh(mp, fhp)
+am_node *mp;
+struct nfs_fh *fhp;
+{
+ struct am_fh *fp = (struct am_fh *) fhp;
+
+ /*
+ * Take the process id
+ */
+ fp->fhh_pid = mypid;
+ /*
+ * .. the map number
+ */
+ fp->fhh_id = mp->am_mapno;
+ /*
+ * .. and the generation number
+ */
+ fp->fhh_gen = mp->am_gen;
+ /*
+ * .. to make a "unique" triple that will never
+ * be reallocated except across reboots (which doesn't matter)
+ * or if we are unlucky enough to be given the same
+ * pid as a previous amd (very unlikely).
+ */
+}
+
+static am_node *find_ap2 P((char *dir, am_node *mp));
+static am_node *find_ap2(dir, mp)
+char *dir;
+am_node *mp;
+{
+ if (mp) {
+ am_node *mp2;
+ if (strcmp(mp->am_path, dir) == 0)
+ return mp;
+
+ if ((mp->am_mnt->mf_flags & MFF_MOUNTED) &&
+ strcmp(mp->am_mnt->mf_mount, dir) == 0)
+ return mp;
+
+ mp2 = find_ap2(dir, mp->am_osib);
+ if (mp2)
+ return mp2;
+ return find_ap2(dir, mp->am_child);
+ }
+
+ return 0;
+}
+
+/*
+ * Find the mount node corresponding
+ * to dir. dir can match either the
+ * automount path or, if the node is
+ * mounted, the mount location.
+ */
+am_node *find_ap P((char *dir));
+am_node *find_ap(dir)
+char *dir;
+{
+ int i;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && (mp->am_flags & AMF_ROOT)) {
+ mp = find_ap2(dir, exported_ap[i]);
+ if (mp)
+ return mp;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Find the mount node corresponding
+ * to the mntfs structure.
+ */
+am_node *find_mf P((mntfs *mf));
+am_node *find_mf(mf)
+mntfs *mf;
+{
+ int i;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt == mf)
+ return mp;
+ }
+ return 0;
+}
+
+/*
+ * Get the filehandle for a particular named directory.
+ * This is used during the bootstrap to tell the kernel
+ * the filehandles of the initial automount points.
+ */
+nfs_fh *root_fh(dir)
+char *dir;
+{
+ static nfs_fh nfh;
+ am_node *mp = root_ap(dir, TRUE);
+ if (mp) {
+ mp_to_fh(mp, &nfh);
+ /*
+ * Patch up PID to match main server...
+ */
+ if (!foreground) {
+ long pid = getppid();
+ ((struct am_fh *) &nfh)->fhh_pid = pid;
+#ifdef DEBUG
+ dlog("root_fh substitutes pid %d", pid);
+#endif
+ }
+ return &nfh;
+ }
+
+ /*
+ * Should never get here...
+ */
+ plog(XLOG_ERROR, "Can't find root filehandle for %s", dir);
+ return 0;
+}
+
+am_node *root_ap(dir, path)
+char *dir;
+int path;
+{
+ am_node *mp = find_ap(dir);
+ if (mp && mp->am_parent == root_node)
+ return mp;
+
+ return 0;
+}
+
+/*
+ * Timeout all nodes waiting on
+ * a given Fserver.
+ */
+void map_flush_srvr P((fserver *fs));
+void map_flush_srvr(fs)
+fserver *fs;
+{
+ int i;
+ int done = 0;
+
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp && mp->am_mnt && mp->am_mnt->mf_server == fs) {
+ plog(XLOG_INFO, "Flushed %s; dependent on %s", mp->am_path, fs->fs_host);
+ mp->am_ttl = clocktime();
+ done = 1;
+ }
+ }
+ if (done)
+ reschedule_timeout_mp();
+}
+
+/*
+ * Mount a top level automount node
+ * by calling lookup in the parent
+ * (root) node which will cause the
+ * automount node to be automounted.
+ */
+int mount_auto_node P((char *dir, voidp arg));
+int mount_auto_node(dir, arg)
+char *dir;
+voidp arg;
+{
+ int error = 0;
+ (void) afs_ops.lookuppn((am_node *) arg, dir, &error, VLOOK_CREATE);
+ if (error > 0) {
+ errno = error; /* XXX */
+ plog(XLOG_ERROR, "Could not mount %s: %m", dir);
+ }
+ return error;
+}
+
+/*
+ * Cause all the top-level mount nodes
+ * to be automounted
+ */
+int mount_exported P((void));
+int mount_exported()
+{
+ /*
+ * Iterate over all the nodes to be started
+ */
+ return root_keyiter((void (*)P((char*,void*))) mount_auto_node, root_node);
+}
+
+/*
+ * Construct top-level node
+ */
+void make_root_node P((void));
+void make_root_node()
+{
+ mntfs *root_mnt;
+ char *rootmap = ROOT_MAP;
+ root_node = exported_ap_alloc();
+
+ /*
+ * Allocate a new map
+ */
+ init_map(root_node, "");
+ /*
+ * Allocate a new mounted filesystem
+ */
+ root_mnt = find_mntfs(&root_ops, (am_opts *) 0, "", rootmap, "", "", "");
+ /*
+ * Replace the initial null reference
+ */
+ free_mntfs(root_node->am_mnt);
+ root_node->am_mnt = root_mnt;
+
+ /*
+ * Initialise the root
+ */
+ if (root_mnt->mf_ops->fs_init)
+ (*root_mnt->mf_ops->fs_init)(root_mnt);
+
+ /*
+ * Mount the root
+ */
+ root_mnt->mf_error = (*root_mnt->mf_ops->mount_fs)(root_node);
+}
+
+/*
+ * Cause all the nodes to be unmounted by timing
+ * them out.
+ */
+void umount_exported(P_void)
+{
+ int i;
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ if (mp) {
+ mntfs *mf = mp->am_mnt;
+ if (mf->mf_flags & MFF_UNMOUNTING) {
+ /*
+ * If this node is being unmounted then
+ * just ignore it. However, this could
+ * prevent amd from finishing if the
+ * unmount gets blocked since the am_node
+ * will never be free'd. am_unmounted needs
+ * telling about this possibility. - XXX
+ */
+ continue;
+ }
+ if (mf && !(mf->mf_ops->fs_flags & FS_DIRECTORY)) {
+ /*
+ * When shutting down this had better
+ * look like a directory, otherwise it
+ * can't be unmounted!
+ */
+ mk_fattr(mp, NFDIR);
+ }
+ if ((--immediate_abort < 0 && !(mp->am_flags & AMF_ROOT) && mp->am_parent) ||
+ (mf->mf_flags & MFF_RESTART)) {
+ /*
+ * Just throw this node away without
+ * bothering to unmount it. If the
+ * server is not known to be up then
+ * don't discard the mounted on directory
+ * or Amd might hang...
+ */
+ if (mf->mf_server &&
+ (mf->mf_server->fs_flags & (FSF_DOWN|FSF_VALID)) != FSF_VALID)
+ mf->mf_flags &= ~MFF_MKMNT;
+ am_unmounted(mp);
+ } else {
+ /*
+ * Any other node gets forcibly
+ * timed out
+ */
+ mp->am_flags &= ~AMF_NOTIMEOUT;
+ mp->am_mnt->mf_flags &= ~MFF_RSTKEEP;
+ mp->am_ttl = 0;
+ mp->am_timeo = 1;
+ mp->am_timeo_w = 0;
+ }
+ }
+ }
+}
+
+static int unmount_node P((am_node *mp));
+static int unmount_node(mp)
+am_node *mp;
+{
+ mntfs *mf = mp->am_mnt;
+ int error;
+
+ if ((mf->mf_flags & MFF_ERROR) || mf->mf_refc > 1) {
+ /*
+ * Just unlink
+ */
+#ifdef DEBUG
+ if (mf->mf_flags & MFF_ERROR)
+ dlog("No-op unmount of error node %s", mf->mf_info);
+#endif /* DEBUG */
+ error = 0;
+ } else {
+#ifdef DEBUG
+ dlog("Unmounting %s (%s)", mf->mf_mount, mf->mf_info);
+#endif /* DEBUG */
+ error = (*mf->mf_ops->umount_fs)(mp);
+ }
+
+ if (error) {
+#ifdef DEBUG
+ errno = error; /* XXX */
+ dlog("%s: unmount: %m", mf->mf_mount);
+#endif /* DEBUG */
+ }
+
+ return error;
+}
+
+#ifdef FLUSH_KERNEL_NAME_CACHE
+static void flush_kernel_name_cache P((am_node*));
+static void flush_kernel_name_cache(mp)
+am_node *mp;
+{
+ int islink = (mp->am_mnt->mf_fattr.type == NFLNK);
+ int isdir = (mp->am_mnt->mf_fattr.type == NFDIR);
+ int elog = 0;
+ if (islink) {
+ if (unlink(mp->am_path) < 0)
+ elog = 1;
+ } else if (isdir) {
+ if (rmdir(mp->am_path) < 0)
+ elog = 1;
+ }
+ if (elog)
+ plog(XLOG_WARNING, "failed to clear \"%s\" from dnlc: %m", mp->am_path);
+}
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+
+static int unmount_node_wrap P((voidp vp));
+static int unmount_node_wrap(vp)
+voidp vp;
+{
+#ifndef FLUSH_KERNEL_NAME_CACHE
+ return unmount_node((am_node*) vp);
+#else /* FLUSH_KERNEL_NAME_CACHE */
+ /*
+ * This code should just say:
+ * return unmount_node((am_node *) vp);
+ *
+ * However...
+ * The kernel keeps a cached copy of filehandles,
+ * and doesn't ever uncache them (apparently). So
+ * when Amd times out a node the kernel will have a
+ * stale filehandle. When the kernel next uses the
+ * filehandle it gets ESTALE.
+ *
+ * The workaround:
+ * Arrange that when a node is removed an unlink or
+ * rmdir is done on that path so that the kernel
+ * cache is done. Yes - yuck.
+ *
+ * This can all be removed (and the background
+ * unmount flag in sfs_ops) if/when the kernel does
+ * something smarter.
+ *
+ * If the unlink or rmdir failed then just log a warning,
+ * don't fail the unmount. This can occur if the kernel
+ * client code decides that the object is still referenced
+ * and should be renamed rather than discarded.
+ *
+ * There is still a race condition here...
+ * if another process is trying to access the same
+ * filesystem at the time we get here, then
+ * it will block, since the MF_UNMOUNTING flag will
+ * be set. That may, or may not, cause the entire
+ * system to deadlock. Hmmm...
+ */
+ am_node *mp = (am_node *) vp;
+ int isauto = mp->am_parent && (mp->am_parent->am_mnt->mf_fattr.type == NFDIR);
+ int error = unmount_node(mp);
+ if (error)
+ return error;
+ if (isauto && (int)amd_state < (int)Finishing)
+ flush_kernel_name_cache(mp);
+
+ return 0;
+#endif /* FLUSH_KERNEL_NAME_CACHE */
+}
+
+static void free_map_if_success(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ am_node *mp = (am_node *) closure;
+ mntfs *mf = mp->am_mnt;
+
+ /*
+ * Not unmounting any more
+ */
+ mf->mf_flags &= ~MFF_UNMOUNTING;
+
+ /*
+ * If a timeout was defered because the underlying filesystem
+ * was busy then arrange for a timeout as soon as possible.
+ */
+ if (mf->mf_flags & MFF_WANTTIMO) {
+ mf->mf_flags &= ~MFF_WANTTIMO;
+ reschedule_timeout_mp();
+ }
+
+ if (term) {
+ plog(XLOG_ERROR, "unmount for %s got signal %d", mp->am_path, term);
+#if defined(DEBUG) && defined(SIGTRAP)
+ /*
+ * dbx likes to put a trap on exit().
+ * Pretend it succeeded for now...
+ */
+ if (term == SIGTRAP) {
+ am_unmounted(mp);
+ }
+#endif /* DEBUG */
+ amd_stats.d_uerr++;
+ } else if (rc) {
+ if (rc == EBUSY) {
+ plog(XLOG_STATS, "\"%s\" on %s still active", mp->am_path, mf->mf_mount);
+ } else {
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: unmount: %m", mp->am_path);
+ }
+ amd_stats.d_uerr++;
+ } else {
+ am_unmounted(mp);
+ }
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) mf);
+}
+
+static int unmount_mp(mp)
+am_node *mp;
+{
+ int was_backgrounded = 0;
+ mntfs *mf = mp->am_mnt;
+
+#ifdef notdef
+ plog(XLOG_INFO, "\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+#endif /* notdef */
+
+ if ((mf->mf_ops->fs_flags & FS_UBACKGROUND) &&
+ (mf->mf_flags & MFF_MOUNTED)) {
+ if (mf->mf_refc == 1 && !FSRV_ISUP(mf->mf_server)) {
+ /*
+ * Don't try to unmount from a server that is known to be down
+ */
+ if (!(mf->mf_flags & MFF_LOGDOWN)) {
+ /* Only log this once, otherwise gets a bit boring */
+ plog(XLOG_STATS, "file server %s is down - timeout of \"%s\" ignored", mf->mf_server->fs_host, mp->am_path);
+ mf->mf_flags |= MFF_LOGDOWN;
+ }
+ } else {
+ /* Clear logdown flag - since the server must be up */
+ mf->mf_flags &= ~MFF_LOGDOWN;
+#ifdef DEBUG
+ dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+ /*dlog("Will background the unmount attempt");*/
+#endif /* DEBUG */
+ /*
+ * Note that we are unmounting this node
+ */
+ mf->mf_flags |= MFF_UNMOUNTING;
+ run_task(unmount_node_wrap, (voidp) mp,
+ free_map_if_success, (voidp) mp);
+ was_backgrounded = 1;
+#ifdef DEBUG
+ dlog("unmount attempt backgrounded");
+#endif /* DEBUG */
+ }
+ } else {
+#ifdef DEBUG
+ dlog("\"%s\" on %s timed out", mp->am_path, mp->am_mnt->mf_mount);
+ dlog("Trying unmount in foreground");
+#endif
+ mf->mf_flags |= MFF_UNMOUNTING;
+ free_map_if_success(unmount_node(mp), 0, (voidp) mp);
+#ifdef DEBUG
+ dlog("unmount attempt done");
+#endif /* DEBUG */
+ }
+
+ return was_backgrounded;
+}
+
+void timeout_mp()
+{
+#define NEVER (time_t) 0
+#define smallest_t(t1, t2) \
+ (t1 != NEVER ? (t2 != NEVER ? (t1 < t2 ? t1 : t2) : t1) : t2)
+#define IGNORE_FLAGS (MFF_MOUNTING|MFF_UNMOUNTING|MFF_RESTART)
+
+ int i;
+ time_t t = NEVER;
+ time_t now = clocktime();
+ int backoff = 0;
+
+#ifdef DEBUG
+ dlog("Timing out automount points...");
+#endif /* DEBUG */
+ for (i = last_used_map; i >= 0; --i) {
+ am_node *mp = exported_ap[i];
+ mntfs *mf;
+ /*
+ * Just continue if nothing mounted, or can't be timed out.
+ */
+ if (!mp || (mp->am_flags & AMF_NOTIMEOUT))
+ continue;
+ /*
+ * Pick up mounted filesystem
+ */
+ mf = mp->am_mnt;
+ if (!mf)
+ continue;
+ /*
+ * Don't delete last reference to a restarted filesystem.
+ */
+ if ((mf->mf_flags & MFF_RSTKEEP) && mf->mf_refc == 1)
+ continue;
+ /*
+ * If there is action on this filesystem then ignore it
+ */
+ if (!(mf->mf_flags & IGNORE_FLAGS)) {
+ int expired = 0;
+ mf->mf_flags &= ~MFF_WANTTIMO;
+#ifdef DEBUG
+ /*dlog("t is initially @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+ if (now >= mp->am_ttl) {
+ if (!backoff) {
+ expired = 1;
+ /*
+ * Move the ttl forward to avoid thrashing effects
+ * on the next call to timeout!
+ */
+ /* sun's -tw option */
+ if (mp->am_timeo_w < 4 * am_timeo_w)
+ mp->am_timeo_w += am_timeo_w;
+ mp->am_ttl = now + mp->am_timeo_w;
+ } else {
+ /*
+ * Just backoff this unmount for
+ * a couple of seconds to avoid
+ * many multiple unmounts being
+ * started in parallel.
+ */
+ mp->am_ttl = now + backoff + 1;
+ }
+ }
+ /*
+ * If the next ttl is smallest, use that
+ */
+ t = smallest_t(t, mp->am_ttl);
+
+#ifdef DEBUG
+ /*dlog("after ttl t is @%d, zero in %d secs", t, t - now);*/
+#endif /* DEBUG */
+
+ if (!mp->am_child && mf->mf_error >= 0 && expired) {
+ /*
+ * If the unmount was backgrounded then
+ * bump the backoff counter.
+ */
+ if (unmount_mp(mp)) {
+ backoff = 2;
+#ifdef DEBUG
+ /*dlog("backing off subsequent unmounts by at least %d seconds", backoff);*/
+#endif
+ }
+ }
+ } else if (mf->mf_flags & MFF_UNMOUNTING) {
+ mf->mf_flags |= MFF_WANTTIMO;
+ }
+ }
+
+ if (t == NEVER) {
+#ifdef DEBUG
+ dlog("No further timeouts");
+#endif /* DEBUG */
+ t = now + ONE_HOUR;
+ }
+
+ /*
+ * Sanity check to avoid runaways.
+ * Absolutely should never get this but
+ * if you do without this trap amd will thrash.
+ */
+ if (t <= now) {
+ t = now + 6; /* XXX */
+ plog(XLOG_ERROR, "Got a zero interval in timeout_mp()!");
+ }
+ /*
+ * XXX - when shutting down, make things happen faster
+ */
+ if ((int)amd_state >= (int)Finishing)
+ t = now + 1;
+#ifdef DEBUG
+ dlog("Next mount timeout in %ds", t - now);
+#endif /* DEBUG */
+
+ timeout_mp_id = timeout(t - now, timeout_mp, 0);
+
+#undef NEVER
+#undef smallest_t
+#undef IGNORE_FLAGS
+}
+
+/*
+ * Cause timeout_mp to be called soonest
+ */
+void reschedule_timeout_mp()
+{
+ if (timeout_mp_id)
+ untimeout(timeout_mp_id);
+ timeout_mp_id = timeout(0, timeout_mp, 0);
+}
diff --git a/usr.sbin/amd/amd/mapc.c b/usr.sbin/amd/amd/mapc.c
new file mode 100644
index 0000000..2155f19
--- /dev/null
+++ b/usr.sbin/amd/amd/mapc.c
@@ -0,0 +1,914 @@
+/*-
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: mapc.c,v 5.2.2.1 1992/02/09 15:08:38 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)mapc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Mount map cache
+ */
+
+#include "am.h"
+#ifdef HAS_REGEXP
+#include RE_HDR
+#endif
+
+/*
+ * Hash table size
+ */
+#define NKVHASH (1 << 2) /* Power of two */
+
+/*
+ * Wildcard key
+ */
+static char wildcard[] = "*";
+
+/*
+ * Map cache types
+ * default, none, incremental, all, regexp
+ * MAPC_RE implies MAPC_ALL and must be numerically
+ * greater.
+ */
+#define MAPC_DFLT 0x000
+#define MAPC_NONE 0x001
+#define MAPC_INC 0x002
+#define MAPC_ROOT 0x004
+#define MAPC_ALL 0x010
+#ifdef HAS_REGEXP
+#define MAPC_RE 0x020
+#define MAPC_ISRE(m) ((m)->alloc == MAPC_RE)
+#else
+#define MAPC_ISRE(m) FALSE
+#endif
+#define MAPC_CACHE_MASK 0x0ff
+#define MAPC_SYNC 0x100
+
+static struct opt_tab mapc_opt[] = {
+ { "all", MAPC_ALL },
+ { "default", MAPC_DFLT },
+ { "inc", MAPC_INC },
+ { "mapdefault", MAPC_DFLT },
+ { "none", MAPC_NONE },
+#ifdef HAS_REGEXP
+ { "re", MAPC_RE },
+ { "regexp", MAPC_RE },
+#endif
+ { "sync", MAPC_SYNC },
+ { 0, 0 }
+};
+
+/*
+ * Lookup recursion
+ */
+#define MREC_FULL 2
+#define MREC_PART 1
+#define MREC_NONE 0
+
+/*
+ * Cache map operations
+ */
+typedef void add_fn P((mnt_map*, char*, char*));
+typedef int init_fn P((char*, time_t*));
+typedef int search_fn P((mnt_map*, char*, char*, char**, time_t*));
+typedef int reload_fn P((mnt_map*, char*, add_fn*));
+typedef int mtime_fn P((char*, time_t*));
+
+static void mapc_sync P((mnt_map*));
+
+/*
+ * Map type
+ */
+typedef struct map_type map_type;
+struct map_type {
+ char *name; /* Name of this map type */
+ init_fn *init; /* Initialisation */
+ reload_fn *reload; /* Reload or fill */
+ search_fn *search; /* Search for new entry */
+ mtime_fn *mtime; /* Find modify time */
+ int def_alloc; /* Default allocation mode */
+};
+
+/*
+ * Key-value pair
+ */
+typedef struct kv kv;
+struct kv {
+ kv *next;
+ char *key;
+ char *val;
+};
+
+struct mnt_map {
+ qelem hdr;
+ int refc; /* Reference count */
+ short flags; /* Allocation flags */
+ short alloc; /* Allocation mode */
+ time_t modify; /* Modify time of map */
+ char *map_name; /* Name of this map */
+ char *wildcard; /* Wildcard value */
+ reload_fn *reload; /* Function to be used for reloads */
+ search_fn *search; /* Function to be used for searching */
+ mtime_fn *mtime; /* Modify time function */
+ kv *kvhash[NKVHASH]; /* Cached data */
+};
+
+/*
+ * Map for root node
+ */
+static mnt_map *root_map;
+
+/*
+ * List of known maps
+ */
+extern qelem map_list_head;
+qelem map_list_head = { &map_list_head, &map_list_head };
+
+/*
+ * Configuration
+ */
+
+/* ROOT MAP */
+static int root_init P((char*, time_t*));
+
+/* FILE MAPS */
+#ifdef HAS_FILE_MAPS
+extern int file_init P((char*, time_t*));
+extern int file_reload P((mnt_map*, char*, add_fn*));
+extern int file_search P((mnt_map*, char*, char*, char**, time_t*));
+extern int file_mtime P((char*, time_t*));
+#endif /* HAS_FILE_MAPS */
+
+/* Network Information Service (NIS) MAPS */
+#ifdef HAS_NIS_MAPS
+extern int nis_init P((char*, time_t*));
+#ifdef HAS_NIS_RELOAD
+extern int nis_reload P((mnt_map*, char*, add_fn*));
+#else
+#define nis_reload error_reload
+#endif
+extern int nis_search P((mnt_map*, char*, char*, char**, time_t*));
+#define nis_mtime nis_init
+#endif /* HAS_NIS_MAPS */
+
+/* NDBM MAPS */
+#ifdef HAS_NDBM_MAPS
+#ifdef OS_HAS_NDBM
+extern int ndbm_init P((char*, time_t*));
+extern int ndbm_search P((mnt_map*, char*, char*, char**, time_t*));
+#define ndbm_mtime ndbm_init
+#endif /* OS_HAS_NDBM */
+#endif /* HAS_NDBM_MAPS */
+
+/* PASSWD MAPS */
+#ifdef HAS_PASSWD_MAPS
+extern int passwd_init P((char*, time_t*));
+extern int passwd_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_PASSWD_MAPS */
+
+/* HESIOD MAPS */
+#ifdef HAS_HESIOD_MAPS
+extern int hesiod_init P((char*, time_t*));
+#ifdef HAS_HESIOD_RELOAD
+extern int hesiod_reload P((mnt_map*, char*, add_fn*));
+#else
+#define hesiod_reload error_reload
+#endif
+extern int hesiod_search P((mnt_map*, char*, char*, char**, time_t*));
+#endif /* HAS_HESIOD_MAPS */
+
+/* UNION MAPS */
+#ifdef HAS_UNION_MAPS
+extern int union_init P((char*, time_t*));
+extern int union_search P((mnt_map*, char*, char*, char**, time_t*));
+extern int union_reload P((mnt_map*, char*, add_fn*));
+#endif /* HAS_UNION_MAPS */
+
+/* ERROR MAP */
+static int error_init P((char*, time_t*));
+static int error_reload P((mnt_map*, char*, add_fn*));
+static int error_search P((mnt_map*, char*, char*, char**, time_t*));
+static int error_mtime P((char*, time_t*));
+
+static map_type maptypes[] = {
+ { "root", root_init, error_reload, error_search, error_mtime, MAPC_ROOT },
+
+#ifdef HAS_PASSWD_MAPS
+ { "passwd", passwd_init, error_reload, passwd_search, error_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_HESIOD_MAPS
+ { "hesiod", hesiod_init, hesiod_reload, hesiod_search, error_mtime, MAPC_ALL },
+#endif
+
+#ifdef HAS_UNION_MAPS
+ { "union", union_init, union_reload, union_search, error_mtime, MAPC_ALL },
+#endif
+
+#ifdef HAS_NIS_MAPS
+ { "nis", nis_init, nis_reload, nis_search, nis_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_NDBM_MAPS
+ { "ndbm", ndbm_init, error_reload, ndbm_search, ndbm_mtime, MAPC_INC },
+#endif
+
+#ifdef HAS_FILE_MAPS
+ { "file", file_init, file_reload, file_search, file_mtime, MAPC_ALL },
+#endif
+
+ { "error", error_init, error_reload, error_search, error_mtime, MAPC_NONE },
+};
+
+/*
+ * Hash function
+ */
+static unsigned int kvhash_of P((char *key));
+static unsigned int kvhash_of(key)
+char *key;
+{
+ unsigned int i, j;
+
+ for (i = 0; j = *key++; i += j)
+ ;
+
+ return i % NKVHASH;
+}
+
+void mapc_showtypes P((FILE *fp));
+void mapc_showtypes(fp)
+FILE *fp;
+{
+ map_type *mt;
+ char *sep = "";
+ for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++) {
+ fprintf(fp, "%s%s", sep, mt->name);
+ sep = ", ";
+ }
+}
+
+static Const char *reg_error = "?";
+void regerror P((Const char *m));
+void regerror(m)
+Const char *m;
+{
+ reg_error = m;
+}
+
+/*
+ * Add key and val to the map m.
+ * key and val are assumed to be safe copies
+ */
+void mapc_add_kv P((mnt_map *m, char *key, char *val));
+void mapc_add_kv(m, key, val)
+mnt_map *m;
+char *key;
+char *val;
+{
+ kv **h;
+ kv *n;
+ int hash = kvhash_of(key);
+
+#ifdef DEBUG
+ dlog("add_kv: %s -> %s", key, val);
+#endif
+
+#ifdef HAS_REGEXP
+ if (MAPC_ISRE(m)) {
+ char keyb[MAXPATHLEN];
+ regexp *re;
+ /*
+ * Make sure the string is bound to the start and end
+ */
+ sprintf(keyb, "^%s$", key);
+ re = regcomp(keyb);
+ if (re == 0) {
+ plog(XLOG_USER, "error compiling RE \"%s\": %s", keyb, reg_error);
+ return;
+ } else {
+ free(key);
+ key = (char *) re;
+ }
+ }
+#endif
+
+ h = &m->kvhash[hash];
+ n = ALLOC(kv);
+ n->key = key;
+ n->val = val;
+ n->next = *h;
+ *h = n;
+}
+
+void mapc_repl_kv P((mnt_map *m, char *key, char *val));
+void mapc_repl_kv(m, key, val)
+mnt_map *m;
+char *key;
+char *val;
+{
+ kv *k;
+
+ /*
+ * Compute the hash table offset
+ */
+ k = m->kvhash[kvhash_of(key)];
+
+ /*
+ * Scan the linked list for the key
+ */
+ while (k && !FSTREQ(k->key, key))
+ k = k->next;
+
+ if (k) {
+ free(k->val);
+ k->val = val;
+ } else {
+ mapc_add_kv(m, key, val);
+ }
+
+}
+
+/*
+ * Search a map for a key.
+ * Calls map specific search routine.
+ * While map is out of date, keep re-syncing.
+ */
+static int search_map P((mnt_map *m, char *key, char **valp));
+static int search_map(m, key, valp)
+mnt_map *m;
+char *key;
+char **valp;
+{
+ int rc;
+ do {
+ rc = (*m->search)(m, m->map_name, key, valp, &m->modify);
+ if (rc < 0) {
+ plog(XLOG_MAP, "Re-synchronizing cache for map %s", m->map_name);
+ mapc_sync(m);
+ }
+ } while (rc < 0);
+
+ return rc;
+}
+
+/*
+ * Do a wildcard lookup in the map and
+ * save the result.
+ */
+static void mapc_find_wildcard P((mnt_map *m));
+static void mapc_find_wildcard(m)
+mnt_map *m;
+{
+ /*
+ * Attempt to find the wildcard entry
+ */
+ int rc = search_map(m, wildcard, &m->wildcard);
+
+ if (rc != 0)
+ m->wildcard = 0;
+}
+
+/*
+ * Make a duplicate reference to an existing map
+ */
+#define mapc_dup(m) ((m)->refc++, (m))
+
+/*
+ * Do a map reload
+ */
+static int mapc_reload_map(m)
+mnt_map *m;
+{
+ int error;
+#ifdef DEBUG
+ dlog("calling map reload on %s", m->map_name);
+#endif
+ error = (*m->reload)(m, m->map_name, mapc_add_kv);
+ if (error)
+ return error;
+ m->wildcard = 0;
+#ifdef DEBUG
+ dlog("calling mapc_search for wildcard");
+#endif
+ error = mapc_search(m, wildcard, &m->wildcard);
+ if (error)
+ m->wildcard = 0;
+ return 0;
+}
+
+/*
+ * Create a new map
+ */
+static mnt_map *mapc_create P((char *map, char *opt));
+static mnt_map *mapc_create(map, opt)
+char *map;
+char *opt;
+{
+ mnt_map *m = ALLOC(mnt_map);
+ map_type *mt;
+ time_t modify;
+ int alloc = 0;
+
+ (void) cmdoption(opt, mapc_opt, &alloc);
+
+ for (mt = maptypes; mt < maptypes+sizeof(maptypes)/sizeof(maptypes[0]); mt++)
+ if ((*mt->init)(map, &modify) == 0)
+ break;
+ /* assert: mt in maptypes */
+
+ m->flags = alloc & ~MAPC_CACHE_MASK;
+ alloc &= MAPC_CACHE_MASK;
+
+ if (alloc == MAPC_DFLT)
+ alloc = mt->def_alloc;
+ switch (alloc) {
+ default:
+ plog(XLOG_USER, "Ambiguous map cache type \"%s\"; using \"inc\"", opt);
+ alloc = MAPC_INC;
+ /* fallthrough... */
+ case MAPC_NONE:
+ case MAPC_INC:
+ case MAPC_ROOT:
+ break;
+ case MAPC_ALL:
+ /*
+ * If there is no support for reload and it was requested
+ * then back off to incremental instead.
+ */
+ if (mt->reload == error_reload) {
+ plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"all\"; using \"inc\"", mt->name);
+ alloc = MAPC_INC;
+ }
+ break;
+#ifdef HAS_REGEXP
+ case MAPC_RE:
+ if (mt->reload == error_reload) {
+ plog(XLOG_WARNING, "Map type \"%s\" does not support cache type \"re\"", mt->name);
+ mt = &maptypes[sizeof(maptypes)/sizeof(maptypes[0]) - 1];
+ /* assert: mt->name == "error" */
+ }
+ break;
+#endif
+ }
+
+#ifdef DEBUG
+ dlog("Map for %s coming from maptype %s", map, mt->name);
+#endif
+
+ m->alloc = alloc;
+ m->reload = mt->reload;
+ m->modify = modify;
+ m->search = alloc >= MAPC_ALL ? error_search : mt->search;
+ m->mtime = mt->mtime;
+ bzero((voidp) m->kvhash, sizeof(m->kvhash));
+ m->map_name = strdup(map);
+ m->refc = 1;
+ m->wildcard = 0;
+
+ /*
+ * synchronize cache with reality
+ */
+ mapc_sync(m);
+
+ return m;
+}
+
+/*
+ * Free the cached data in a map
+ */
+static void mapc_clear P((mnt_map *m));
+static void mapc_clear(m)
+mnt_map *m;
+{
+ int i;
+
+ /*
+ * For each of the hash slots, chain
+ * along free'ing the data.
+ */
+ for (i = 0; i < NKVHASH; i++) {
+ kv *k = m->kvhash[i];
+ while (k) {
+ kv *n = k->next;
+ free((voidp) k->key);
+ if (k->val)
+ free((voidp) k->val);
+ free((voidp) k);
+ k = n;
+ }
+ }
+ /*
+ * Zero the hash slots
+ */
+ bzero((voidp) m->kvhash, sizeof(m->kvhash));
+ /*
+ * Free the wildcard if it exists
+ */
+ if (m->wildcard) {
+ free(m->wildcard);
+ m->wildcard = 0;
+ }
+}
+
+/*
+ * Find a map, or create one if it does not exist
+ */
+mnt_map *mapc_find P((char *map, char *opt));
+mnt_map *mapc_find(map, opt)
+char *map;
+char *opt;
+{
+ mnt_map *m;
+
+ /*
+ * Search the list of known maps to see if
+ * it has already been loaded. If it is found
+ * then return a duplicate reference to it.
+ * Otherwise make a new map as required and
+ * add it to the list of maps
+ */
+ ITER(m, mnt_map, &map_list_head)
+ if (STREQ(m->map_name, map))
+ return mapc_dup(m);
+
+ m = mapc_create(map, opt);
+ ins_que(&m->hdr, &map_list_head);
+ return m;
+}
+
+/*
+ * Free a map.
+ */
+void mapc_free P((mnt_map *m));
+void mapc_free(m)
+mnt_map *m;
+{
+ /*
+ * Decrement the reference count.
+ * If the reference count hits zero
+ * then throw the map away.
+ */
+ if (m && --m->refc == 0) {
+ mapc_clear(m);
+ free((voidp) m->map_name);
+ rem_que(&m->hdr);
+ free((voidp) m);
+ }
+}
+
+/*
+ * Search the map for the key.
+ * Put a safe copy in *pval or return
+ * an error code
+ */
+int mapc_meta_search P((mnt_map *m, char *key, char **pval, int recurse));
+int mapc_meta_search(m, key, pval, recurse)
+mnt_map *m;
+char *key;
+char **pval;
+int recurse;
+{
+ int error = 0;
+ kv *k = 0;
+
+ /*
+ * Firewall
+ */
+ if (!m) {
+ plog(XLOG_ERROR, "Null map request for %s", key);
+ return ENOENT;
+ }
+
+ if (m->flags & MAPC_SYNC) {
+ /*
+ * Get modify time...
+ */
+ time_t t;
+ error = (*m->mtime)(m->map_name, &t);
+ if (error || t > m->modify) {
+ m->modify = t;
+ plog(XLOG_INFO, "Map %s is out of date", m->map_name);
+ mapc_sync(m);
+ }
+ }
+
+ if (!MAPC_ISRE(m)) {
+ /*
+ * Compute the hash table offset
+ */
+ k = m->kvhash[kvhash_of(key)];
+
+ /*
+ * Scan the linked list for the key
+ */
+ while (k && !FSTREQ(k->key, key)) k = k->next;
+
+ }
+#ifdef HAS_REGEXP
+ else if (recurse == MREC_FULL) {
+ /*
+ * Try for an RE match against the entire map.
+ * Note that this will be done in a "random"
+ * order.
+ */
+
+ int i;
+
+ for (i = 0; i < NKVHASH; i++) {
+ k = m->kvhash[i];
+ while (k) {
+ if (regexec((regexp *) k->key, key))
+ break;
+ k = k->next;
+ }
+ if (k)
+ break;
+ }
+ }
+#endif
+
+ /*
+ * If found then take a copy
+ */
+ if (k) {
+ if (k->val)
+ *pval = strdup(k->val);
+ else
+ error = ENOENT;
+ } else if (m->alloc >= MAPC_ALL) {
+ /*
+ * If the entire map is cached then this
+ * key does not exist.
+ */
+ error = ENOENT;
+ } else {
+ /*
+ * Otherwise search the map. If we are
+ * in incremental mode then add the key
+ * to the cache.
+ */
+ error = search_map(m, key, pval);
+ if (!error && m->alloc == MAPC_INC)
+ mapc_add_kv(m, strdup(key), strdup(*pval));
+ }
+
+ /*
+ * If an error, and a wildcard exists,
+ * and the key is not internal then
+ * return a copy of the wildcard.
+ */
+ if (error > 0) {
+ if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
+ char wildname[MAXPATHLEN];
+ char *subp;
+ if (*key == '/')
+ return error;
+ /*
+ * Keep chopping sub-directories from the RHS
+ * and replacing with "/ *" and repeat the lookup.
+ * For example:
+ * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
+ */
+ strcpy(wildname, key);
+ while (error && (subp = strrchr(wildname, '/'))) {
+ strcpy(subp, "/*");
+#ifdef DEBUG
+ dlog("mapc recurses on %s", wildname);
+#endif
+ error = mapc_meta_search(m, wildname, pval, MREC_PART);
+ if (error)
+ *subp = 0;
+ }
+ if (error > 0 && m->wildcard) {
+ *pval = strdup(m->wildcard);
+ error = 0;
+ }
+ }
+ }
+
+ return error;
+}
+
+int mapc_search P((mnt_map *m, char *key, char **pval));
+int mapc_search(m, key, pval)
+mnt_map *m;
+char *key;
+char **pval;
+{
+ return mapc_meta_search(m, key, pval, MREC_FULL);
+}
+
+/*
+ * Get map cache in sync with physical representation
+ */
+static void mapc_sync P((mnt_map *m));
+static void mapc_sync(m)
+mnt_map *m;
+{
+ if (m->alloc != MAPC_ROOT) {
+ mapc_clear(m);
+
+ if (m->alloc >= MAPC_ALL)
+ if (mapc_reload_map(m))
+ m->alloc = MAPC_INC;
+ /*
+ * Attempt to find the wildcard entry
+ */
+ if (m->alloc < MAPC_ALL)
+ mapc_find_wildcard(m);
+ }
+}
+
+/*
+ * Reload all the maps
+ * Called when Amd gets hit by a SIGHUP.
+ */
+void mapc_reload(P_void);
+void mapc_reload()
+{
+ mnt_map *m;
+
+ /*
+ * For all the maps,
+ * Throw away the existing information.
+ * Do a reload
+ * Find the wildcard
+ */
+ ITER(m, mnt_map, &map_list_head)
+ mapc_sync(m);
+}
+
+/*
+ * Root map.
+ * The root map is used to bootstrap amd.
+ * All the require top-level mounts are added
+ * into the root map and then the map is iterated
+ * and a lookup is done on all the mount points.
+ * This causes the top level mounts to be automounted.
+ */
+
+static int root_init P((char *map, time_t *tp));
+static int root_init(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = clocktime();
+ return strcmp(map, ROOT_MAP) == 0 ? 0 : ENOENT;
+}
+
+/*
+ * Add a new entry to the root map
+ *
+ * dir - directory (key)
+ * opts - mount options
+ * map - map name
+ */
+void root_newmap P((char *dir, char *opts, char *map));
+void root_newmap(dir, opts, map)
+char *dir;
+char *opts;
+char *map;
+{
+ char str[MAXPATHLEN];
+
+ /*
+ * First make sure we have a root map to talk about...
+ */
+ if (!root_map)
+ root_map = mapc_find(ROOT_MAP, "mapdefault");
+
+ /*
+ * Then add the entry...
+ */
+ dir = strdup(dir);
+ if (map)
+ sprintf(str, "cache:=mapdefault;type:=toplvl;fs:=\"%s\";%s",
+ map, opts ? opts : "");
+ else
+ strcpy(str, opts);
+ mapc_repl_kv(root_map, dir, strdup(str));
+}
+
+int mapc_keyiter P((mnt_map *m, void (*fn)(char*,voidp), voidp arg));
+int mapc_keyiter(m, fn, arg)
+mnt_map *m;
+void (*fn)P((char*, voidp));
+voidp arg;
+{
+ int i;
+ int c = 0;
+
+ for (i = 0; i < NKVHASH; i++) {
+ kv *k = m->kvhash[i];
+ while (k) {
+ (*fn)(k->key, arg);
+ k = k->next;
+ c++;
+ }
+ }
+
+ return c;
+}
+
+/*
+ * Iterate of the the root map
+ * and call (*fn)() on the key
+ * of all the nodes.
+ * Finally throw away the root map.
+ */
+int root_keyiter P((void (*fn)(char*,voidp), voidp arg));
+int root_keyiter(fn, arg)
+void (*fn)P((char*,voidp));
+voidp arg;
+{
+ if (root_map) {
+ int c = mapc_keyiter(root_map, fn, arg);
+#ifdef notdef
+ mapc_free(root_map);
+ root_map = 0;
+#endif
+ return c;
+ }
+ return 0;
+}
+
+/*
+ * Error map
+ */
+static int error_init P((char *map, time_t *tp));
+static int error_init(map, tp)
+char *map;
+time_t *tp;
+{
+ plog(XLOG_USER, "No source data for map %s", map);
+ *tp = 0;
+ return 0;
+}
+
+/*ARGSUSED*/
+static int error_search P((mnt_map *m, char *map, char *key, char **pval, time_t *tp));
+static int error_search(m, map, key, pval, tp)
+mnt_map *m;
+char *map;
+char *key;
+char **pval;
+time_t *tp;
+{
+ return ENOENT;
+}
+
+/*ARGSUSED*/
+static int error_reload P((mnt_map *m, char *map, add_fn *fn));
+static int error_reload(m, map, fn)
+mnt_map *m;
+char *map;
+add_fn *fn;
+{
+ return ENOENT;
+}
+
+static int error_mtime P((char *map, time_t *tp));
+static int error_mtime(map, tp)
+char *map;
+time_t *tp;
+{
+ *tp = 0;
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/misc_rpc.c b/usr.sbin/amd/amd/misc_rpc.c
new file mode 100644
index 0000000..0fb10c8
--- /dev/null
+++ b/usr.sbin/amd/amd/misc_rpc.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc_rpc.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc_rpc.c,v 5.2.2.1 1992/02/09 15:08:40 jsp beta $
+ *
+ */
+
+/*
+ * Additions to Sun RPC.
+ */
+
+#include "am.h"
+
+void rpc_msg_init P((struct rpc_msg *mp, u_long prog, u_long vers, u_long proc));
+void rpc_msg_init(mp, prog, vers, proc)
+struct rpc_msg *mp;
+unsigned long prog, vers, proc;
+{
+ /*
+ * Initialise the message
+ */
+ bzero((voidp) mp, sizeof(*mp));
+ mp->rm_xid = 0;
+ mp->rm_direction = CALL;
+ mp->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ mp->rm_call.cb_prog = prog;
+ mp->rm_call.cb_vers = vers;
+ mp->rm_call.cb_proc = proc;
+}
+
+/*
+ * Field reply to call to mountd
+ */
+int pickup_rpc_reply P((voidp pkt, int len, voidp where, xdrproc_t where_xdr));
+int pickup_rpc_reply(pkt, len, where, where_xdr)
+voidp pkt;
+int len;
+voidp where;
+xdrproc_t where_xdr;
+{
+ XDR reply_xdr;
+ int ok;
+ struct rpc_err err;
+ struct rpc_msg reply_msg;
+ int error = 0;
+
+ /*bzero((voidp) &err, sizeof(err));*/
+ bzero((voidp) &reply_msg, sizeof(reply_msg));
+
+ reply_msg.acpted_rply.ar_results.where = (caddr_t) where;
+ reply_msg.acpted_rply.ar_results.proc = where_xdr;
+
+ xdrmem_create(&reply_xdr, pkt, len, XDR_DECODE);
+
+ ok = xdr_replymsg(&reply_xdr, &reply_msg);
+ if (!ok) {
+ error = EIO;
+ goto drop;
+ }
+ _seterr_reply(&reply_msg, &err);
+ if (err.re_status != RPC_SUCCESS) {
+ error = EIO;
+ goto drop;
+ }
+
+drop:
+ if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED &&
+ reply_msg.acpted_rply.ar_verf.oa_base) {
+ reply_xdr.x_op = XDR_FREE;
+ (void)xdr_opaque_auth(&reply_xdr,
+ &reply_msg.acpted_rply.ar_verf);
+ }
+ xdr_destroy(&reply_xdr);
+
+ return error;
+}
+
+int make_rpc_packet P((char *buf, int buflen, unsigned long proc,
+ struct rpc_msg *mp, voidp arg, xdrproc_t arg_xdr, AUTH *auth));
+int make_rpc_packet(buf, buflen, proc, mp, arg, arg_xdr, auth)
+char *buf;
+int buflen;
+unsigned long proc;
+struct rpc_msg *mp;
+voidp arg;
+xdrproc_t arg_xdr;
+AUTH *auth;
+{
+ XDR msg_xdr;
+ int len;
+
+ xdrmem_create(&msg_xdr, buf, buflen, XDR_ENCODE);
+ /*
+ * Basic protocol header
+ */
+ if (!xdr_callhdr(&msg_xdr, mp))
+ return -EIO;
+ /*
+ * Called procedure number
+ */
+ if (!xdr_enum(&msg_xdr, &proc))
+ return -EIO;
+ /*
+ * Authorization
+ */
+ if (!AUTH_MARSHALL(auth, &msg_xdr))
+ return -EIO;
+ /*
+ * Arguments
+ */
+ if (!(*arg_xdr)(&msg_xdr, arg))
+ return -EIO;
+ /*
+ * Determine length
+ */
+ len = xdr_getpos(&msg_xdr);
+ /*
+ * Throw away xdr
+ */
+ xdr_destroy(&msg_xdr);
+ return len;
+}
+
+
+/*
+ * Early RPC seems to be missing these..
+ * Extracted from the RPC 3.9 sources as indicated
+ */
+
+#ifdef NEED_XDR_POINTER
+/* @(#)xdr_reference.c 1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ * What's sent is actually a union:
+ *
+ * union object_pointer switch (boolean b) {
+ * case TRUE: object_data data;
+ * case FALSE: void nothing;
+ * }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(xdrs,objpp,obj_size,xdr_obj)
+ register XDR *xdrs;
+ char **objpp;
+ u_int obj_size;
+ xdrproc_t xdr_obj;
+{
+
+ bool_t more_data;
+
+ more_data = (*objpp != NULL);
+ if (! xdr_bool(xdrs,&more_data)) {
+ return (FALSE);
+ }
+ if (! more_data) {
+ *objpp = NULL;
+ return (TRUE);
+ }
+ return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
+#endif /* NEED_XDR_POINTER */
+
+#ifdef NEED_CLNT_SPERRNO
+/* @(#)clnt_perror.c 1.1 87/11/04 3.9 RPCSRC */
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part. Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California 94043
+ */
+
+struct rpc_errtab {
+ enum clnt_stat status;
+ char *message;
+};
+
+static struct rpc_errtab rpc_errlist[] = {
+ { RPC_SUCCESS,
+ "RPC: Success" },
+ { RPC_CANTENCODEARGS,
+ "RPC: Can't encode arguments" },
+ { RPC_CANTDECODERES,
+ "RPC: Can't decode result" },
+ { RPC_CANTSEND,
+ "RPC: Unable to send" },
+ { RPC_CANTRECV,
+ "RPC: Unable to receive" },
+ { RPC_TIMEDOUT,
+ "RPC: Timed out" },
+ { RPC_VERSMISMATCH,
+ "RPC: Incompatible versions of RPC" },
+ { RPC_AUTHERROR,
+ "RPC: Authentication error" },
+ { RPC_PROGUNAVAIL,
+ "RPC: Program unavailable" },
+ { RPC_PROGVERSMISMATCH,
+ "RPC: Program/version mismatch" },
+ { RPC_PROCUNAVAIL,
+ "RPC: Procedure unavailable" },
+ { RPC_CANTDECODEARGS,
+ "RPC: Server can't decode arguments" },
+ { RPC_SYSTEMERROR,
+ "RPC: Remote system error" },
+ { RPC_UNKNOWNHOST,
+ "RPC: Unknown host" },
+/* { RPC_UNKNOWNPROTO,
+ "RPC: Unknown protocol" },*/
+ { RPC_PMAPFAILURE,
+ "RPC: Port mapper failure" },
+ { RPC_PROGNOTREGISTERED,
+ "RPC: Program not registered"},
+ { RPC_FAILED,
+ "RPC: Failed (unspecified error)"}
+};
+
+
+/*
+ * This interface for use by clntrpc
+ */
+char *
+clnt_sperrno(stat)
+ enum clnt_stat stat;
+{
+ int i;
+
+ for (i = 0; i < sizeof(rpc_errlist)/sizeof(struct rpc_errtab); i++) {
+ if (rpc_errlist[i].status == stat) {
+ return (rpc_errlist[i].message);
+ }
+ }
+ return ("RPC: (unknown error code)");
+}
+
+#endif /* NEED_CLNT_SPERRNO */
+
diff --git a/usr.sbin/amd/amd/mntfs.c b/usr.sbin/amd/amd/mntfs.c
new file mode 100644
index 0000000..ef8f17f
--- /dev/null
+++ b/usr.sbin/amd/amd/mntfs.c
@@ -0,0 +1,367 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: mntfs.c,v 5.2.2.1 1992/02/09 15:08:42 jsp beta $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)mntfs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+
+#include "am.h"
+
+extern qelem mfhead;
+qelem mfhead = { &mfhead, &mfhead };
+
+int mntfs_allocated;
+
+#ifdef notdef
+/*
+ * This is the default attributes field which
+ * is copied into every new node to be created.
+ * The individual filesystem fs_init() routines
+ * patch the copy to represent the particular
+ * details for the relevant filesystem type
+ */
+static struct fattr gen_fattr = {
+ NFDIR, /* type */
+ NFSMODE_DIR | 0555, /* mode */
+ 2, /* nlink */
+ 0, /* uid */
+ 0, /* gid */
+ 512, /* size */
+ 4096, /* blocksize */
+ 0, /* rdev */
+ 1, /* blocks */
+ 0, /* fsid */
+ 0, /* fileid */
+ { 0, 0 }, /* atime */
+ { 0, 0 }, /* mtime */
+ { 0, 0 }, /* ctime */
+};
+#endif /* notdef */
+
+mntfs *dup_mntfs(mf)
+mntfs *mf;
+{
+ if (mf->mf_refc == 0) {
+ if (mf->mf_cid)
+ untimeout(mf->mf_cid);
+ mf->mf_cid = 0;
+#ifdef notdef
+ mf->mf_error = -1;
+ mf->mf_flags &= ~MFF_ERROR;
+#endif
+ }
+ mf->mf_refc++;
+ return mf;
+}
+
+static void init_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+static void init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mf->mf_ops = ops;
+ mf->mf_fo = mo;
+ mf->mf_mount = strdup(mp);
+ mf->mf_info = strdup(info);
+ mf->mf_auto = strdup(auto_opts);
+ mf->mf_mopts = strdup(mopts);
+ mf->mf_remopts = strdup(remopts);
+ mf->mf_refc = 1;
+ mf->mf_flags = 0;
+ mf->mf_error = -1;
+ mf->mf_cid = 0;
+ mf->mf_private = 0;
+ mf->mf_prfree = 0;
+#ifdef notdef
+ mf->mf_attr.status = NFS_OK;
+ mf->mf_fattr = gen_fattr;
+ mf->mf_fattr.fsid = 42;
+ mf->mf_fattr.fileid = 0;
+ mf->mf_fattr.atime.seconds = clocktime();
+ mf->mf_fattr.atime.useconds = 0;
+ mf->mf_fattr.mtime = mf->mf_fattr.ctime = mf->mf_fattr.atime;
+#endif
+
+ if (ops->ffserver)
+ mf->mf_server = (*ops->ffserver)(mf);
+ else
+ mf->mf_server = 0;
+}
+
+static mntfs *alloc_mntfs P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+static mntfs *alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf = ALLOC(mntfs);
+ init_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts);
+ ins_que(&mf->mf_q, &mfhead);
+ mntfs_allocated++;
+
+ return mf;
+}
+
+mntfs *find_mntfs P((am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+mntfs *find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts)
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf;
+
+#ifdef DEBUG
+ dlog("Locating mntfs reference to %s", mp);
+#endif /* DEBUG */
+ ITER(mf, mntfs, &mfhead) {
+ if (STREQ(mf->mf_mount, mp)) {
+ /*
+ * Handle cases where error ops are involved
+ */
+ if (ops == &efs_ops) {
+ /*
+ * If the existing ops are not efs_ops
+ * then continue...
+ */
+ if (mf->mf_ops != &efs_ops)
+ continue;
+ } else /* ops != &efs_ops */ {
+ /*
+ * If the existing ops are efs_ops
+ * then continue...
+ */
+ if (mf->mf_ops == &efs_ops)
+ continue;
+ }
+
+ if ((mf->mf_flags & MFF_RESTART) && amd_state == Run) {
+ /*
+ * Restart a previously mounted filesystem.
+ */
+ mntfs *mf2 = alloc_mntfs(&ifs_ops, mo, mp, info, auto_opts, mopts, remopts);
+#ifdef DEBUG
+ dlog("Restarting filesystem %s", mf->mf_mount);
+#endif /* DEBUG */
+ /*
+ * Remember who we are restarting
+ */
+ mf2->mf_private = (voidp) dup_mntfs(mf);
+ mf2->mf_prfree = free_mntfs;
+ return mf2;
+ }
+ mf->mf_fo = mo;
+ if (!(mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING))) {
+ fserver *fs;
+ mf->mf_flags &= ~MFF_ERROR;
+ mf->mf_error = -1;
+ mf->mf_auto = strealloc(mf->mf_auto, auto_opts);
+ mf->mf_mopts = strealloc(mf->mf_mopts, mopts);
+ mf->mf_remopts = strealloc(mf->mf_remopts, remopts);
+ mf->mf_info = strealloc(mf->mf_info, info);
+ if (mf->mf_private && mf->mf_prfree) {
+ (*mf->mf_prfree)(mf->mf_private);
+ mf->mf_private = 0;
+ }
+ fs = ops->ffserver ? (*ops->ffserver)(mf) : (fserver *) 0;
+ if (mf->mf_server)
+ free_srvr(mf->mf_server);
+ mf->mf_server = fs;
+ }
+ return dup_mntfs(mf);
+ }
+ }
+
+ return alloc_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
+}
+
+mntfs *new_mntfs()
+{
+ return alloc_mntfs(&efs_ops, (am_opts *) 0, "//nil//", ".", "", "", "");
+}
+
+static void uninit_mntfs(mf, rmd)
+mntfs *mf;
+int rmd;
+{
+ if (mf->mf_mount) free((voidp) mf->mf_mount);
+ if (mf->mf_auto) free((voidp) mf->mf_auto);
+ if (mf->mf_mopts) free((voidp) mf->mf_mopts);
+ if (mf->mf_remopts) free((voidp) mf->mf_remopts);
+ if (mf->mf_info) free((voidp) mf->mf_info);
+ if (mf->mf_private && mf->mf_prfree)
+ (*mf->mf_prfree)(mf->mf_private);
+ /*
+ * Clean up any directories that were made
+ */
+ if (rmd && (mf->mf_flags & MFF_MKMNT))
+ rmdirs(mf->mf_mount);
+
+ /*
+ * Clean up the file server
+ */
+ if (mf->mf_server)
+ free_srvr(mf->mf_server);
+
+ /*
+ * Don't do a callback on this mount
+ */
+ if (mf->mf_cid) {
+ untimeout(mf->mf_cid);
+ mf->mf_cid = 0;
+ }
+}
+
+static void discard_mntfs(mf)
+mntfs *mf;
+{
+ rem_que(&mf->mf_q);
+ /*
+ * Free memory
+ */
+ uninit_mntfs(mf, TRUE);
+ free((voidp) mf);
+
+ --mntfs_allocated;
+}
+
+void flush_mntfs()
+{
+ mntfs *mf;
+
+ mf = FIRST(mntfs, &mfhead);
+ while (mf != HEAD(mntfs, &mfhead)) {
+ mntfs *mf2 = mf;
+ mf = NEXT(mntfs, mf);
+ if (mf2->mf_refc == 0 && mf2->mf_cid)
+ discard_mntfs(mf2);
+ }
+}
+
+void free_mntfs(mf)
+mntfs *mf;
+{
+ if (--mf->mf_refc == 0) {
+ if (mf->mf_flags & MFF_MOUNTED) {
+ int quoted;
+ mf->mf_flags &= ~MFF_MOUNTED;
+
+ /*
+ * Record for posterity
+ */
+ quoted = strchr(mf->mf_info, ' ') != 0; /* cheap */
+ plog(XLOG_INFO, "%s%s%s %sed fstype %s from %s",
+ quoted ? "\"" : "",
+ mf->mf_info,
+ quoted ? "\"" : "",
+ mf->mf_error ? "discard" : "unmount",
+ mf->mf_ops->fs_type, mf->mf_mount);
+ }
+
+ if (mf->mf_ops->fs_flags & FS_DISCARD) {
+#ifdef DEBUG
+ dlog("Immediately discarding mntfs for %s", mf->mf_mount);
+#endif /* DEBUG */
+ discard_mntfs(mf);
+ } else {
+#ifdef DEBUG
+ if (mf->mf_flags & MFF_RESTART) {
+ dlog("Discarding remount hook for %s", mf->mf_mount);
+ } else {
+ dlog("Discarding last mntfs reference to %s fstype %s",
+ mf->mf_mount, mf->mf_ops->fs_type);
+ }
+ if (mf->mf_flags & (MFF_MOUNTED|MFF_MOUNTING|MFF_UNMOUNTING))
+ dlog("mntfs reference for %s still active", mf->mf_mount);
+#endif /* DEBUG */
+ mf->mf_cid = timeout(ALLOWED_MOUNT_TIME, discard_mntfs, (voidp) mf);
+ }
+ }
+}
+
+mntfs *realloc_mntfs P((mntfs *mf, am_ops *ops, am_opts *mo, char *mp, char *info, char *auto_opts, char *mopts, char *remopts));
+mntfs *realloc_mntfs(mf, ops, mo, mp, info, auto_opts, mopts, remopts)
+mntfs *mf;
+am_ops *ops;
+am_opts *mo;
+char *mp;
+char *info;
+char *auto_opts;
+char *mopts;
+char *remopts;
+{
+ mntfs *mf2;
+ if (mf->mf_refc == 1 && mf->mf_ops == &ifs_ops && STREQ(mf->mf_mount, mp)) {
+ /*
+ * If we are inheriting then just return
+ * the same node...
+ */
+ return mf;
+ }
+
+ /*
+ * Re-use the existing mntfs if it is mounted.
+ * This traps a race in nfsx.
+ */
+ if (mf->mf_ops != &efs_ops &&
+ (mf->mf_flags & MFF_MOUNTED) &&
+ !FSRV_ISDOWN(mf->mf_server)) {
+ mf->mf_fo = mo;
+ return mf;
+ }
+
+ mf2 = find_mntfs(ops, mo, mp, info, auto_opts, mopts, remopts);
+ free_mntfs(mf);
+ return mf2;
+}
diff --git a/usr.sbin/amd/amd/mount_fs.c b/usr.sbin/amd/amd/mount_fs.c
new file mode 100644
index 0000000..43a0625
--- /dev/null
+++ b/usr.sbin/amd/amd/mount_fs.c
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mount_fs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount_fs.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $
+ *
+ */
+
+#include "am.h"
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#include <sys/mount.h>
+
+#include <sys/stat.h>
+
+/*
+ * Standard mount flags
+ */
+#ifdef hpux
+/*
+ * HP-UX has an annoying feature of printing
+ * error msgs on /dev/console
+ */
+#undef M_NOSUID
+#endif /* hpux */
+
+struct opt_tab mnt_flags[] = {
+ { "ro", M_RDONLY },
+#ifdef M_CACHE
+ { "nocache", M_NOCACHE },
+#endif /* M_CACHE */
+#ifdef M_GRPID
+ { "grpid", M_GRPID },
+#endif /* M_GRPID */
+#ifdef M_MULTI
+ { "multi", M_MULTI },
+#endif /* M_MULTI */
+#ifdef M_NODEV
+ { "nodev", M_NODEV },
+#endif /* M_NODEV */
+#ifdef M_NOEXEC
+ { "noexec", M_NOEXEC },
+#endif /* M_NOEXEC */
+#ifdef M_NOSUB
+ { "nosub", M_NOSUB },
+#endif /* M_NOSUB */
+#ifdef M_NOSUID
+ { "nosuid", M_NOSUID },
+#endif /* M_NOSUID */
+#ifdef M_SYNC
+ { "sync", M_SYNC },
+#endif /* M_SYNC */
+ { 0, 0 }
+};
+
+int compute_mount_flags(mnt)
+struct mntent *mnt;
+{
+ struct opt_tab *opt;
+ int flags;
+#ifdef NFS_4
+ flags = M_NEWTYPE;
+#else
+ flags = 0;
+#endif /* NFS_4 */
+
+ /*
+ * Crack basic mount options
+ */
+ for (opt = mnt_flags; opt->opt; opt++)
+ flags |= hasmntopt(mnt, opt->opt) ? opt->flag : 0;
+
+ return flags;
+}
+
+int mount_fs P((struct mntent *mnt, int flags, caddr_t mnt_data, int retry, MTYPE_TYPE type));
+int mount_fs(mnt, flags, mnt_data, retry, type)
+struct mntent *mnt;
+int flags;
+caddr_t mnt_data;
+int retry;
+MTYPE_TYPE type;
+{
+ int error = 0;
+#ifdef MNTINFO_DEV
+ struct stat stb;
+ char *xopts = 0;
+#endif /* MNTINFO_DEV */
+
+#ifdef DEBUG
+#ifdef NFS_4
+ dlog("%s fstype %s (%s) flags %#x (%s)",
+ mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#else
+ dlog("%s fstype %d (%s) flags %#x (%s)",
+ mnt->mnt_dir, type, mnt->mnt_type, flags, mnt->mnt_opts);
+#endif /* NFS_4 */
+#endif /* DEBUG */
+
+ /*
+ * Fake some mount table entries for the automounter
+ */
+#ifdef FASCIST_DF_COMMAND
+ /*
+ * Some systems have a df command which blows up when
+ * presented with an unknown mount type.
+ */
+ if (STREQ(mnt->mnt_type, MNTTYPE_AUTO)) {
+ /*
+ * Try it with the normal name
+ */
+ mnt->mnt_type = FASCIST_DF_COMMAND;
+ }
+#endif /* FASCIST_DF_COMMAND */
+
+again:
+ clock_valid = 0;
+ error = MOUNT_TRAP(type, mnt, flags, mnt_data);
+ if (error < 0)
+ plog(XLOG_ERROR, "%s: mount: %m", mnt->mnt_dir);
+ if (error < 0 && --retry > 0) {
+ sleep(1);
+ goto again;
+ }
+ if (error < 0) {
+#ifdef notdef
+ if (automount)
+ going_down(errno);
+#endif
+ return errno;
+ }
+
+#ifdef UPDATE_MTAB
+#ifdef MNTINFO_DEV
+ /*
+ * Add the extra dev= field to the mount table.
+ */
+ if (lstat(mnt->mnt_dir, &stb) == 0) {
+ char *zopts = (char *) xmalloc(strlen(mnt->mnt_opts) + 32);
+ xopts = mnt->mnt_opts;
+ if (sizeof(stb.st_dev) == 2) {
+ /* e.g. SunOS 4.1 */
+ sprintf(zopts, "%s,%s=%s%04lx", xopts, MNTINFO_DEV,
+ MNTINFO_PREF, (u_long) stb.st_dev & 0xffff);
+ } else {
+ /* e.g. System Vr4 */
+ sprintf(zopts, "%s,%s=%s%08lx", xopts, MNTINFO_DEV,
+ MNTINFO_PREF, (u_long) stb.st_dev);
+ }
+ mnt->mnt_opts = zopts;
+ }
+#endif /* MNTINFO_DEV */
+
+#ifdef FIXUP_MNTENT
+ /*
+ * Additional fields in struct mntent
+ * are fixed up here
+ */
+ FIXUP_MNTENT(mnt);
+#endif
+
+ write_mntent(mnt);
+#ifdef MNTINFO_DEV
+ if (xopts) {
+ free(mnt->mnt_opts);
+ mnt->mnt_opts = xopts;
+ }
+#endif /* MNTINFO_DEV */
+#endif /* UPDATE_MTAB */
+
+ return 0;
+}
+
+#ifdef NEED_MNTOPT_PARSER
+/*
+ * Some systems don't provide these to the user,
+ * but amd needs them, so...
+ *
+ * From: Piete Brooks <pb@cl.cam.ac.uk>
+ */
+
+#include <ctype.h>
+
+static char *nextmntopt(p)
+char **p;
+{
+ char *cp = *p;
+ char *rp;
+ /*
+ * Skip past white space
+ */
+ while (*cp && isspace(*cp))
+ cp++;
+ /*
+ * Word starts here
+ */
+ rp = cp;
+ /*
+ * Scan to send of string or separator
+ */
+ while (*cp && *cp != ',')
+ cp++;
+ /*
+ * If separator found the overwrite with nul char.
+ */
+ if (*cp) {
+ *cp = '\0';
+ cp++;
+ }
+ /*
+ * Return value for next call
+ */
+ *p = cp;
+ return rp;
+}
+
+char *hasmntopt(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+ char t[MNTMAXSTR];
+ char *f;
+ char *o = t;
+ int l = strlen(opt);
+ strcpy(t, mnt->mnt_opts);
+
+ while (*(f = nextmntopt(&o)))
+ if (strncmp(opt, f, l) == 0)
+ return f - t + mnt->mnt_opts;
+
+ return 0;
+}
+#endif /* NEED_MNTOPT_PARSER */
+
+#ifdef MOUNT_HELPER_SOURCE
+#include MOUNT_HELPER_SOURCE
+#endif /* MOUNT_HELPER_SOURCE */
diff --git a/usr.sbin/amd/amd/mtab.c b/usr.sbin/amd/amd/mtab.c
new file mode 100644
index 0000000..43b3a26
--- /dev/null
+++ b/usr.sbin/amd/amd/mtab.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mtab.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab.c,v 5.2.2.1 1992/02/09 15:08:45 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+/*
+ * Firewall /etc/mtab entries
+ */
+void mnt_free P((struct mntent *mp));
+void mnt_free(mp)
+struct mntent *mp;
+{
+ free(mp->mnt_fsname);
+ free(mp->mnt_dir);
+ free(mp->mnt_type);
+ free(mp->mnt_opts);
+ free((voidp) mp);
+}
+
+/*
+ * Discard memory allocated for mount list
+ */
+void discard_mntlist P((mntlist *mp));
+void discard_mntlist(mp)
+mntlist *mp;
+{
+ mntlist *mp2;
+
+ while (mp2 = mp) {
+ mp = mp->mnext;
+ if (mp2->mnt)
+ mnt_free(mp2->mnt);
+ free((voidp) mp2);
+ }
+}
+
+/*
+ * Throw away a mount list
+ */
+void free_mntlist P((mntlist *mp));
+void free_mntlist(mp)
+mntlist *mp;
+{
+ discard_mntlist(mp);
+ unlock_mntlist();
+}
+
+/*
+ * Utility routine which determines the value of a
+ * numeric option in the mount options (such as port=%d).
+ * Returns 0 if the option is not specified.
+ */
+int hasmntval P((struct mntent *mnt, char *opt));
+int hasmntval(mnt, opt)
+struct mntent *mnt;
+char *opt;
+{
+ char *str = hasmntopt(mnt, opt);
+ if (str) {
+ char *eq = strchr(str, '=');
+ if (eq)
+ return atoi(eq+1);
+ else
+ plog(XLOG_USER, "bad numeric option \"%s\" in \"%s\"", opt, str);
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/nfs_ops.c b/usr.sbin/amd/amd/nfs_ops.c
new file mode 100644
index 0000000..bcfd7a5
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_ops.c
@@ -0,0 +1,809 @@
+/*-
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: nfs_ops.c,v 5.2.2.2 1992/05/31 16:35:05 jsp Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)nfs_ops.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+#include <sys/stat.h>
+
+#ifdef HAS_NFS
+
+#define NFS
+#define NFSCLIENT
+#ifdef NFS_3
+typedef nfs_fh fhandle_t;
+#endif /* NFS_3 */
+#ifdef NFS_HDR
+#include NFS_HDR
+#endif /* NFS_HDR */
+#include <sys/mount.h>
+#include "mount.h"
+
+/*
+ * Network file system
+ */
+
+/*
+ * Convert from nfsstat to UN*X error code
+ */
+#define unx_error(e) ((int)(e))
+
+/*
+ * The NFS layer maintains a cache of file handles.
+ * This is *fundamental* to the implementation and
+ * also allows quick remounting when a filesystem
+ * is accessed soon after timing out.
+ *
+ * The NFS server layer knows to flush this cache
+ * when a server goes down so avoiding stale handles.
+ *
+ * Each cache entry keeps a hard reference to
+ * the corresponding server. This ensures that
+ * the server keepalive information is maintained.
+ *
+ * The copy of the sockaddr_in here is taken so
+ * that the port can be twiddled to talk to mountd
+ * instead of portmap or the NFS server as used
+ * elsewhere.
+ * The port# is flushed if a server goes down.
+ * The IP address is never flushed - we assume
+ * that the address of a mounted machine never
+ * changes. If it does, then you have other
+ * problems...
+ */
+typedef struct fh_cache fh_cache;
+struct fh_cache {
+ qelem fh_q; /* List header */
+ voidp fh_wchan; /* Wait channel */
+ int fh_error; /* Valid data? */
+ int fh_id; /* Unique id */
+ int fh_cid; /* Callout id */
+ struct fhstatus fh_handle; /* Handle on filesystem */
+ struct sockaddr_in fh_sin; /* Address of mountd */
+ fserver *fh_fs; /* Server holding filesystem */
+ char *fh_path; /* Filesystem on host */
+};
+
+/*
+ * FH_TTL is the time a file handle will remain in the cache since
+ * last being used. If the file handle becomes invalid, then it
+ * will be flushed anyway.
+ */
+#define FH_TTL (5 * 60) /* five minutes */
+#define FH_TTL_ERROR (30) /* 30 seconds */
+
+static int fh_id = 0;
+#define FHID_ALLOC() (++fh_id)
+extern qelem fh_head;
+qelem fh_head = { &fh_head, &fh_head };
+
+static int call_mountd P((fh_cache*, unsigned long, fwd_fun, voidp));
+
+AUTH *nfs_auth;
+
+static fh_cache *find_nfs_fhandle_cache P((voidp idv, int done));
+static fh_cache *find_nfs_fhandle_cache(idv, done)
+voidp idv;
+int done;
+{
+ fh_cache *fp, *fp2 = 0;
+ int id = (int) idv;
+
+ ITER(fp, fh_cache, &fh_head) {
+ if (fp->fh_id == id) {
+ fp2 = fp;
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ if (fp2) {
+ dlog("fh cache gives fp %#x, fs %s", fp2, fp2->fh_path);
+ } else {
+ dlog("fh cache search failed");
+ }
+#endif /* DEBUG */
+
+ if (fp2 && !done) {
+ fp2->fh_error = ETIMEDOUT;
+ return 0;
+ }
+
+ return fp2;
+}
+
+/*
+ * Called when a filehandle appears
+ */
+static void got_nfs_fh P((voidp pkt, int len, struct sockaddr_in *sa,
+ struct sockaddr_in *ia, voidp idv, int done));
+static void got_nfs_fh(pkt, len, sa, ia, idv, done)
+voidp pkt;
+int len;
+struct sockaddr_in *sa, *ia;
+voidp idv;
+int done;
+{
+ fh_cache *fp = find_nfs_fhandle_cache(idv, done);
+ if (fp) {
+ fp->fh_error = pickup_rpc_reply(pkt, len, (voidp) &fp->fh_handle, xdr_fhstatus);
+ if (!fp->fh_error) {
+#ifdef DEBUG
+ dlog("got filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+ /*
+ * Wakeup anything sleeping on this filehandle
+ */
+ if (fp->fh_wchan) {
+#ifdef DEBUG
+ dlog("Calling wakeup on %#x", fp->fh_wchan);
+#endif /* DEBUG */
+ wakeup(fp->fh_wchan);
+ }
+ }
+ }
+}
+
+void flush_nfs_fhandle_cache P((fserver *fs));
+void flush_nfs_fhandle_cache(fs)
+fserver *fs;
+{
+ fh_cache *fp;
+ ITER(fp, fh_cache, &fh_head) {
+ if (fp->fh_fs == fs || fs == 0) {
+ fp->fh_sin.sin_port = (u_short) 0;
+ fp->fh_error = -1;
+ }
+ }
+}
+
+static void discard_fh P((fh_cache *fp));
+static void discard_fh(fp)
+fh_cache *fp;
+{
+ rem_que(&fp->fh_q);
+#ifdef DEBUG
+ dlog("Discarding filehandle for %s:%s", fp->fh_fs->fs_host, fp->fh_path);
+#endif /* DEBUG */
+ free_srvr(fp->fh_fs);
+ free((voidp) fp->fh_path);
+ free((voidp) fp);
+}
+
+/*
+ * Determine the file handle for a node
+ */
+static int prime_nfs_fhandle_cache P((char *path, fserver *fs, struct fhstatus *fhbuf, voidp wchan));
+static int prime_nfs_fhandle_cache(path, fs, fhbuf, wchan)
+char *path;
+fserver *fs;
+struct fhstatus *fhbuf;
+voidp wchan;
+{
+ fh_cache *fp, *fp_save = 0;
+ int error;
+ int reuse_id = FALSE;
+
+#ifdef DEBUG
+ dlog("Searching cache for %s:%s", fs->fs_host, path);
+#endif /* DEBUG */
+
+ /*
+ * First search the cache
+ */
+ ITER(fp, fh_cache, &fh_head) {
+ if (fs == fp->fh_fs && strcmp(path, fp->fh_path) == 0) {
+ switch (fp->fh_error) {
+ case 0:
+ error = fp->fh_error = unx_error(fp->fh_handle.fhs_status);
+ if (error == 0) {
+ if (fhbuf)
+ bcopy((voidp) &fp->fh_handle, (voidp) fhbuf,
+ sizeof(fp->fh_handle));
+ if (fp->fh_cid)
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+ } else if (error == EACCES) {
+ /*
+ * Now decode the file handle return code.
+ */
+ plog(XLOG_INFO, "Filehandle denied for \"%s:%s\"",
+ fs->fs_host, path);
+ } else {
+ errno = error; /* XXX */
+ plog(XLOG_INFO, "Filehandle error for \"%s:%s\": %m",
+ fs->fs_host, path);
+ }
+
+ /*
+ * The error was returned from the remote mount daemon.
+ * Policy: this error will be cached for now...
+ */
+ return error;
+
+ case -1:
+ /*
+ * Still thinking about it, but we can re-use.
+ */
+ fp_save = fp;
+ reuse_id = TRUE;
+ break;
+
+ default:
+ /*
+ * Return the error.
+ * Policy: make sure we recompute if required again
+ * in case this was caused by a network failure.
+ * This can thrash mountd's though... If you find
+ * your mountd going slowly then:
+ * 1. Add a fork() loop to main.
+ * 2. Remove the call to innetgr() and don't use
+ * netgroups, especially if you don't use YP.
+ */
+ error = fp->fh_error;
+ fp->fh_error = -1;
+ return error;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Not in cache
+ */
+ if (fp_save) {
+ fp = fp_save;
+ /*
+ * Re-use existing slot
+ */
+ untimeout(fp->fh_cid);
+ free_srvr(fp->fh_fs);
+ free(fp->fh_path);
+ } else {
+ fp = ALLOC(fh_cache);
+ bzero((voidp) fp, sizeof(*fp));
+ ins_que(&fp->fh_q, &fh_head);
+ }
+ if (!reuse_id)
+ fp->fh_id = FHID_ALLOC();
+ fp->fh_wchan = wchan;
+ fp->fh_error = -1;
+ fp->fh_cid = timeout(FH_TTL, discard_fh, (voidp) fp);
+
+ /*
+ * If the address has changed then don't try to re-use the
+ * port information
+ */
+ if (fp->fh_sin.sin_addr.s_addr != fs->fs_ip->sin_addr.s_addr) {
+ fp->fh_sin = *fs->fs_ip;
+ fp->fh_sin.sin_port = 0;
+ }
+ fp->fh_fs = dup_srvr(fs);
+ fp->fh_path = strdup(path);
+
+ error = call_mountd(fp, MOUNTPROC_MNT, got_nfs_fh, wchan);
+ if (error) {
+ /*
+ * Local error - cache for a short period
+ * just to prevent thrashing.
+ */
+ untimeout(fp->fh_cid);
+ fp->fh_cid = timeout(error < 0 ? 2 * ALLOWED_MOUNT_TIME : FH_TTL_ERROR,
+ discard_fh, (voidp) fp);
+ fp->fh_error = error;
+ } else {
+ error = fp->fh_error;
+ }
+ return error;
+}
+
+int make_nfs_auth P((void))
+{
+#ifdef HAS_NFS_QUALIFIED_NAMES
+ /*
+ * From: Chris Metcalf <metcalf@masala.lcs.mit.edu>
+ * Use hostd, not just hostname. Note that uids
+ * and gids and the gidlist are type *int* and not the
+ * system uid_t and gid_t types.
+ */
+ static int group_wheel = 0;
+ nfs_auth = authunix_create(hostd, 0, 0, 1, &group_wheel);
+#else
+ nfs_auth = authunix_create_default();
+#endif
+ if (!nfs_auth)
+ return ENOBUFS;
+ return 0;
+}
+
+static int call_mountd P((fh_cache *fp, u_long proc, fwd_fun f, voidp wchan));
+static int call_mountd(fp, proc, f, wchan)
+fh_cache *fp;
+u_long proc;
+fwd_fun f;
+voidp wchan;
+{
+ struct rpc_msg mnt_msg;
+ int len;
+ char iobuf[8192];
+ int error;
+
+ if (!nfs_auth) {
+ error = make_nfs_auth();
+ if (error)
+ return error;
+ }
+
+ if (fp->fh_sin.sin_port == 0) {
+ u_short port;
+ error = nfs_srvr_port(fp->fh_fs, &port, wchan);
+ if (error)
+ return error;
+ fp->fh_sin.sin_port = port;
+ }
+
+ rpc_msg_init(&mnt_msg, MOUNTPROG, MOUNTVERS, (unsigned long) 0);
+ len = make_rpc_packet(iobuf, sizeof(iobuf), proc,
+ &mnt_msg, (voidp) &fp->fh_path, xdr_nfspath, nfs_auth);
+
+ if (len > 0) {
+ error = fwd_packet(MK_RPC_XID(RPC_XID_MOUNTD, fp->fh_id),
+ (voidp) iobuf, len, &fp->fh_sin, &fp->fh_sin, (voidp) fp->fh_id, f);
+ } else {
+ error = -len;
+ }
+/*
+ * It may be the case that we're sending to the wrong MOUNTD port. This
+ * occurs if mountd is restarted on the server after the port has been
+ * looked up and stored in the filehandle cache somewhere. The correct
+ * solution, if we're going to cache port numbers is to catch the ICMP
+ * port unreachable reply from the server and cause the portmap request
+ * to be redone. The quick solution here is to invalidate the MOUNTD
+ * port.
+ */
+ fp->fh_sin.sin_port = 0;
+
+ return error;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * NFS needs the local filesystem, remote filesystem
+ * remote hostname.
+ * Local filesystem defaults to remote and vice-versa.
+ */
+static char *nfs_match(fo)
+am_opts *fo;
+{
+ char *xmtab;
+ if (fo->opt_fs && !fo->opt_rfs)
+ fo->opt_rfs = fo->opt_fs;
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "nfs: no remote filesystem specified");
+ return FALSE;
+ }
+ if (!fo->opt_rhost) {
+ plog(XLOG_USER, "nfs: no remote host specified");
+ return FALSE;
+ }
+ /*
+ * Determine magic cookie to put in mtab
+ */
+ xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
+ sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
+#ifdef DEBUG
+ dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
+ fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
+#endif /* DEBUG */
+
+ return xmtab;
+}
+
+/*
+ * Initialise am structure for nfs
+ */
+static int nfs_init(mf)
+mntfs *mf;
+{
+ if (!mf->mf_private) {
+ int error;
+ struct fhstatus fhs;
+
+ char *colon = strchr(mf->mf_info, ':');
+ if (colon == 0)
+ return ENOENT;
+
+ error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) mf);
+ if (!error) {
+ mf->mf_private = (voidp) ALLOC(fhstatus);
+ mf->mf_prfree = (void (*)()) free;
+ bcopy((voidp) &fhs, mf->mf_private, sizeof(fhs));
+ }
+ return error;
+ }
+
+ return 0;
+}
+
+int mount_nfs_fh P((struct fhstatus *fhp, char *dir, char *fs_name, char *opts, mntfs *mf));
+int mount_nfs_fh(fhp, dir, fs_name, opts, mf)
+struct fhstatus *fhp;
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+ struct nfs_args nfs_args;
+ struct mntent mnt;
+ int retry;
+ char *colon;
+ /*char *path;*/
+ char host[MAXHOSTNAMELEN + MAXPATHLEN + 2];
+ fserver *fs = mf->mf_server;
+ int flags;
+ char *xopts;
+ int error;
+#ifdef notdef
+ unsigned short port;
+#endif /* notdef */
+
+ MTYPE_TYPE type = MOUNT_TYPE_NFS;
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args)); /* Paranoid */
+
+ /*
+ * Extract host name to give to kernel
+ */
+ if (!(colon = strchr(fs_name, ':')))
+ return ENOENT;
+#ifndef NFS_ARGS_NEEDS_PATH
+ *colon = '\0';
+#endif
+ strncpy(host, fs_name, sizeof(host));
+#ifndef NFS_ARGS_NEEDS_PATH
+ *colon = ':';
+#endif /* NFS_ARGS_NEEDS_PATH */
+ /*path = colon + 1;*/
+
+ if (mf->mf_remopts && *mf->mf_remopts && !islocalnet(fs->fs_ip->sin_addr.s_addr))
+ xopts = strdup(mf->mf_remopts);
+ else
+ xopts = strdup(opts);
+
+ bzero((voidp) &nfs_args, sizeof(nfs_args));
+
+ mnt.mnt_dir = dir;
+ mnt.mnt_fsname = fs_name;
+ mnt.mnt_type = MTAB_TYPE_NFS;
+ mnt.mnt_opts = xopts;
+ mnt.mnt_freq = 0;
+ mnt.mnt_passno = 0;
+
+ retry = hasmntval(&mnt, "retry");
+ if (retry <= 0)
+ retry = 1; /* XXX */
+
+/*again:*/
+
+ /*
+ * set mount args
+ */
+ NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp->fhstatus_u.fhs_fhandle);
+
+#ifdef ULTRIX_HACK
+ nfs_args.optstr = mnt.mnt_opts;
+#endif /* ULTRIX_HACK */
+
+ nfs_args.hostname = host;
+ nfs_args.flags |= NFSMNT_HOSTNAME;
+#ifdef HOSTNAMESZ
+ /*
+ * Most kernels have a name length restriction.
+ */
+ if (strlen(host) >= HOSTNAMESZ)
+ strcpy(host + HOSTNAMESZ - 3, "..");
+#endif /* HOSTNAMESZ */
+
+ if (nfs_args.rsize = hasmntval(&mnt, "rsize"))
+ nfs_args.flags |= NFSMNT_RSIZE;
+
+ if (nfs_args.wsize = hasmntval(&mnt, "wsize"))
+ nfs_args.flags |= NFSMNT_WSIZE;
+
+ if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
+ nfs_args.flags |= NFSMNT_TIMEO;
+
+ if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
+ nfs_args.flags |= NFSMNT_RETRANS;
+
+#ifdef NFSMNT_BIODS
+ if (nfs_args.biods = hasmntval(&mnt, "biods"))
+ nfs_args.flags |= NFSMNT_BIODS;
+
+#endif /* NFSMNT_BIODS */
+
+#ifdef NFSMNT_MAXGRPS
+ if (nfs_args.maxgrouplist = hasmntval(&mnt, "maxgroups"))
+ nfs_args.flags |= NFSMNT_MAXGRPS;
+#endif /* NFSMNT_MAXGRPS */
+
+#ifdef notdef
+/*
+ * This isn't supported by the ping algorithm yet.
+ * In any case, it is all done in nfs_init().
+ */
+ if (port = hasmntval(&mnt, "port"))
+ sin.sin_port = htons(port);
+ else
+ sin.sin_port = htons(NFS_PORT); /* XXX should use portmapper */
+#endif /* notdef */
+
+ if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
+ nfs_args.flags |= NFSMNT_SOFT;
+
+#ifdef NFSMNT_SPONGY
+ if (hasmntopt(&mnt, "spongy") != NULL) {
+ nfs_args.flags |= NFSMNT_SPONGY;
+ if (nfs_args.flags & NFSMNT_SOFT) {
+ plog(XLOG_USER, "Mount opts soft and spongy are incompatible - soft ignored");
+ nfs_args.flags &= ~NFSMNT_SOFT;
+ }
+ }
+#endif /* MNTOPT_SPONGY */
+
+#ifdef MNTOPT_INTR
+ if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
+ nfs_args.flags |= NFSMNT_INT;
+#endif /* MNTOPT_INTR */
+
+#ifdef MNTOPT_NODEVS
+ if (hasmntopt(&mnt, MNTOPT_NODEVS) != NULL)
+ nfs_args.flags |= NFSMNT_NODEVS;
+#endif /* MNTOPT_NODEVS */
+
+#ifdef MNTOPT_COMPRESS
+ if (hasmntopt(&mnt, "compress") != NULL)
+ nfs_args.flags |= NFSMNT_COMPRESS;
+#endif /* MNTOPT_COMPRESS */
+
+#ifdef MNTOPT_NOCONN
+ if (hasmntopt(&mnt, "noconn") != NULL)
+ nfs_args.flags |= NFSMNT_NOCONN;
+#endif /* MNTOPT_NOCONN */
+
+#ifdef NFSMNT_PGTHRESH
+ if (nfs_args.pg_thresh = hasmntval(&mnt, "pgthresh"))
+ nfs_args.flags |= NFSMNT_PGTHRESH;
+#endif /* NFSMNT_PGTHRESH */
+
+ NFS_SA_DREF(nfs_args, fs->fs_ip);
+
+ flags = compute_mount_flags(&mnt);
+
+#ifdef NFSMNT_NOCTO
+ if (hasmntopt(&mnt, "nocto") != NULL)
+ nfs_args.flags |= NFSMNT_NOCTO;
+#endif /* NFSMNT_NOCTO */
+
+#ifdef HAS_TCP_NFS
+ if (hasmntopt(&mnt, "tcp") != NULL)
+ nfs_args.sotype = SOCK_STREAM;
+#endif /* HAS_TCP_NFS */
+
+
+#ifdef ULTRIX_HACK
+ /*
+ * Ultrix passes the flags argument as part of the
+ * mount data structure, rather than using the
+ * flags argument to the system call. This is
+ * confusing...
+ */
+ if (!(nfs_args.flags & NFSMNT_PGTHRESH)) {
+ nfs_args.pg_thresh = 64; /* 64k - XXX */
+ nfs_args.flags |= NFSMNT_PGTHRESH;
+ }
+ nfs_args.gfs_flags = flags;
+ flags &= M_RDONLY;
+ if (flags & M_RDONLY)
+ nfs_args.flags |= NFSMNT_RONLY;
+#endif /* ULTRIX_HACK */
+
+ error = mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
+ free(xopts);
+ return error;
+}
+
+static int mount_nfs(dir, fs_name, opts, mf)
+char *dir;
+char *fs_name;
+char *opts;
+mntfs *mf;
+{
+#ifdef notdef
+ int error;
+ struct fhstatus fhs;
+ char *colon;
+
+ if (!(colon = strchr(fs_name, ':')))
+ return ENOENT;
+
+#ifdef DEBUG
+ dlog("locating fhandle for %s", fs_name);
+#endif /* DEBUG */
+ error = prime_nfs_fhandle_cache(colon+1, mf->mf_server, &fhs, (voidp) 0);
+
+ if (error)
+ return error;
+
+ return mount_nfs_fh(&fhs, dir, fs_name, opts, mf);
+#endif
+ if (!mf->mf_private) {
+ plog(XLOG_ERROR, "Missing filehandle for %s", fs_name);
+ return EINVAL;
+ }
+
+ return mount_nfs_fh((struct fhstatus *) mf->mf_private, dir, fs_name, opts, mf);
+}
+
+static int nfs_fmount(mf)
+mntfs *mf;
+{
+ int error;
+
+ error = mount_nfs(mf->mf_mount, mf->mf_info, mf->mf_mopts, mf);
+
+#ifdef DEBUG
+ if (error) {
+ errno = error;
+ dlog("mount_nfs: %m");
+ }
+#endif /* DEBUG */
+ return error;
+}
+
+static int nfs_fumount(mf)
+mntfs *mf;
+{
+ int error = UMOUNT_FS(mf->mf_mount);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void nfs_umounted(mp)
+am_node *mp;
+{
+#ifdef INFORM_MOUNTD
+ /*
+ * Don't bother to inform remote mountd
+ * that we are finished. Until a full
+ * track of filehandles is maintained
+ * the mountd unmount callback cannot
+ * be done correctly anyway...
+ */
+
+ mntfs *mf = mp->am_mnt;
+ fserver *fs;
+ char *colon, *path;
+
+ if (mf->mf_error || mf->mf_refc > 1)
+ return;
+
+ fs = mf->mf_server;
+
+ /*
+ * Call the mount daemon on the server to
+ * announce that we are not using the fs any more.
+ *
+ * This is *wrong*. The mountd should be called
+ * when the fhandle is flushed from the cache, and
+ * a reference held to the cached entry while the
+ * fs is mounted...
+ */
+ colon = path = strchr(mf->mf_info, ':');
+ if (fs && colon) {
+ fh_cache f;
+#ifdef DEBUG
+ dlog("calling mountd for %s", mf->mf_info);
+#endif /* DEBUG */
+ *path++ = '\0';
+ f.fh_path = path;
+ f.fh_sin = *fs->fs_ip;
+ f.fh_sin.sin_port = (u_short) 0;
+ f.fh_fs = fs;
+ f.fh_id = 0;
+ f.fh_error = 0;
+ (void) prime_nfs_fhandle_cache(colon+1, mf->mf_server, (struct fhstatus *) 0, (voidp) mf);
+ (void) call_mountd(&f, MOUNTPROC_UMNT, (fwd_fun) 0, (voidp) 0);
+ *colon = ':';
+ }
+#endif /* INFORM_MOUNTD */
+
+#ifdef KICK_KERNEL
+ /* This should go into the mainline code, not in nfs_ops... */
+
+ /*
+ * Run lstat over the underlying directory in
+ * case this was a direct mount. This will
+ * get the kernel back in sync with reality.
+ */
+ if (mp->am_parent && mp->am_parent->am_path &&
+ STREQ(mp->am_parent->am_mnt->mf_ops->fs_type, "direct")) {
+ struct stat stb;
+ int pid;
+ if ((pid = background()) == 0) {
+ if (lstat(mp->am_parent->am_path, &stb) < 0) {
+ plog(XLOG_ERROR, "lstat(%s) after unmount: %m", mp->am_parent->am_path);
+#ifdef DEBUG
+ } else {
+ dlog("hack lstat(%s): ok", mp->am_parent->am_path);
+#endif /* DEBUG */
+ }
+ _exit(0);
+ }
+ }
+#endif /* KICK_KERNEL */
+}
+
+/*
+ * Network file system
+ */
+am_ops nfs_ops = {
+ "nfs",
+ nfs_match,
+ nfs_init,
+ auto_fmount,
+ nfs_fmount,
+ auto_fumount,
+ nfs_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* nfs_readlink */
+ 0, /* nfs_mounted */
+ nfs_umounted,
+ find_nfs_srvr,
+ FS_MKMNT|FS_BACKGROUND|FS_AMQINFO
+};
+
+#endif /* HAS_NFS */
diff --git a/usr.sbin/amd/amd/nfs_start.c b/usr.sbin/amd/amd/nfs_start.c
new file mode 100644
index 0000000..13d36a1
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_start.c
@@ -0,0 +1,435 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfs_start.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_start.c,v 5.2.2.1 1992/02/09 15:08:51 jsp beta $
+ *
+ */
+
+#include "am.h"
+#include "amq.h"
+#include <sys/signal.h>
+#include <setjmp.h>
+extern jmp_buf select_intr;
+extern int select_intr_valid;
+
+#ifdef HAS_TFS
+/*
+ * Use replacement for RPC/UDP transport
+ * so that we do NFS gatewaying.
+ */
+#define svcudp_create svcudp2_create
+extern SVCXPRT *svcudp2_create P((int));
+#endif /* HAS_TFS */
+
+extern void nfs_program_2();
+extern void amq_program_1();
+
+unsigned short nfs_port;
+SVCXPRT *nfsxprt;
+
+extern int fwd_sock;
+int max_fds = -1;
+
+#define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
+
+#ifdef DEBUG
+/*
+ * Check that we are not burning resources
+ */
+static void checkup(P_void)
+{
+
+static int max_fd = 0;
+static char *max_mem = 0;
+
+ int next_fd = dup(0);
+ extern caddr_t sbrk P((int));
+ caddr_t next_mem = sbrk(0);
+ close(next_fd);
+
+ /*if (max_fd < 0) {
+ max_fd = next_fd;
+ } else*/ if (max_fd < next_fd) {
+ dlog("%d new fds allocated; total is %d",
+ next_fd - max_fd, next_fd);
+ max_fd = next_fd;
+ }
+
+ /*if (max_mem == 0) {
+ max_mem = next_mem;
+ } else*/ if (max_mem < next_mem) {
+ dlog("%#x bytes of memory allocated; total is %#x (%d pages)",
+ next_mem - max_mem,
+ next_mem,
+ ((int)next_mem+getpagesize()-1)/getpagesize());
+ max_mem = next_mem;
+ }
+}
+#endif /* DEBUG */
+
+static int do_select(smask, fds, fdp, tvp)
+int smask;
+int fds;
+int *fdp;
+struct timeval *tvp;
+{
+ int sig;
+ int nsel;
+ if (sig = setjmp(select_intr)) {
+ select_intr_valid = 0;
+ /* Got a signal */
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ amd_state = Finishing;
+ reschedule_timeout_mp();
+ break;
+ }
+ nsel = -1;
+ errno = EINTR;
+ } else {
+ select_intr_valid = 1;
+ /*
+ * Invalidate the current clock value
+ */
+ clock_valid = 0;
+ /*
+ * Allow interrupts. If a signal
+ * occurs, then it will cause a longjmp
+ * up above.
+ */
+ (void) sigsetmask(smask);
+ /*
+ * Wait for input
+ */
+ nsel = select(fds, fdp, (int *) 0, (int *) 0,
+ tvp->tv_sec ? tvp : (struct timeval *) 0);
+
+ }
+
+ (void) sigblock(MASKED_SIGS);
+
+ /*
+ * Perhaps reload the cache?
+ */
+ if (do_mapc_reload < clocktime()) {
+ mapc_reload();
+ do_mapc_reload = clocktime() + ONE_HOUR;
+ }
+ return nsel;
+}
+
+/*
+ * Determine whether anything is left in
+ * the RPC input queue.
+ */
+static int rpc_pending_now()
+{
+ struct timeval tvv;
+ int nsel;
+#ifdef FD_SET
+ fd_set readfds;
+
+ FD_ZERO(&readfds);
+ FD_SET(fwd_sock, &readfds);
+#else
+ int readfds = (1 << fwd_sock);
+#endif /* FD_SET */
+
+ tvv.tv_sec = tvv.tv_usec = 0;
+ nsel = select(max_fds+1, &readfds, (int *) 0, (int *) 0, &tvv);
+ if (nsel < 1)
+ return(0);
+#ifdef FD_SET
+ if (FD_ISSET(fwd_sock, &readfds))
+ return(1);
+#else
+ if (readfds & (1 << fwd_sock))
+ return(1);
+#endif
+ return(0);
+}
+
+static serv_state run_rpc(P_void)
+{
+ int dtbsz = max_fds + 1;
+ int smask = sigblock(MASKED_SIGS);
+
+ next_softclock = clocktime();
+
+ amd_state = Run;
+
+ /*
+ * Keep on trucking while we are in Run mode. This state
+ * is switched to Quit after all the file systems have
+ * been unmounted.
+ */
+ while ((int)amd_state <= (int)Finishing) {
+ struct timeval tvv;
+ int nsel;
+ time_t now;
+#ifdef RPC_4
+ fd_set readfds;
+ readfds = svc_fdset;
+ FD_SET(fwd_sock, &readfds);
+#else
+#ifdef FD_SET
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ readfds.fds_bits[0] = svc_fds;
+ FD_SET(fwd_sock, &readfds);
+#else
+ int readfds = svc_fds | (1 << fwd_sock);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+
+#ifdef DEBUG
+ checkup();
+#endif /* DEBUG */
+
+ /*
+ * If the full timeout code is not called,
+ * then recompute the time delta manually.
+ */
+ now = clocktime();
+
+ if (next_softclock <= now) {
+ if (amd_state == Finishing)
+ umount_exported();
+ tvv.tv_sec = softclock();
+ } else {
+ tvv.tv_sec = next_softclock - now;
+ }
+ tvv.tv_usec = 0;
+
+ if (amd_state == Finishing && last_used_map < 0) {
+ flush_mntfs();
+ amd_state = Quit;
+ break;
+ }
+
+#ifdef DEBUG
+ if (tvv.tv_sec)
+ dlog("Select waits for %ds", tvv.tv_sec);
+ else
+ dlog("Select waits for Godot");
+#endif /* DEBUG */
+
+ nsel = do_select(smask, dtbsz, &readfds, &tvv);
+
+
+ switch (nsel) {
+ case -1:
+ if (errno == EINTR) {
+#ifdef DEBUG
+ dlog("select interrupted");
+#endif /* DEBUG */
+ continue;
+ }
+ perror("select");
+ break;
+
+ case 0:
+#ifdef DEBUG
+ /*dlog("select returned 0");*/
+#endif /* DEBUG */
+ break;
+
+ default:
+ /* Read all pending NFS responses at once to avoid
+ having responses queue up as a consequence of
+ retransmissions. */
+#ifdef FD_SET
+ if (FD_ISSET(fwd_sock, &readfds)) {
+ FD_CLR(fwd_sock, &readfds);
+#else
+ if (readfds & (1 << fwd_sock)) {
+ readfds &= ~(1 << fwd_sock);
+#endif
+ --nsel;
+ do {
+ fwd_reply();
+ } while (rpc_pending_now() > 0);
+ }
+
+ if (nsel) {
+ /*
+ * Anything left must be a normal
+ * RPC request.
+ */
+#ifdef RPC_4
+ svc_getreqset(&readfds);
+#else
+#ifdef FD_SET
+ svc_getreq(readfds.fds_bits[0]);
+#else
+ svc_getreq(readfds);
+#endif /* FD_SET */
+#endif /* RPC_4 */
+ }
+ break;
+ }
+ }
+
+ (void) sigsetmask(smask);
+
+ if (amd_state == Quit)
+ amd_state = Done;
+
+ return amd_state;
+}
+
+static int bindnfs_port(so)
+int so;
+{
+ unsigned short port;
+ int error = bind_resv_port(so, &port);
+ if (error == 0)
+ nfs_port = port;
+ return error;
+}
+
+void unregister_amq(P_void)
+{
+#ifdef DEBUG
+ Debug(D_AMQ)
+#endif /* DEBUG */
+ (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION);
+}
+
+int mount_automounter(ppid)
+int ppid;
+{
+ int so = socket(AF_INET, SOCK_DGRAM, 0);
+ SVCXPRT *amqp;
+ int nmount;
+
+ if (so < 0 || bindnfs_port(so) < 0) {
+ perror("Can't create privileged nfs port");
+ return 1;
+ }
+
+ if ((nfsxprt = svcudp_create(so)) == NULL ||
+ (amqp = svcudp_create(so)) == NULL) {
+ plog(XLOG_FATAL, "cannot create rpc/udp service");
+ return 2;
+ }
+
+ if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) {
+ plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
+ return 3;
+ }
+
+ /*
+ * Start RPC forwarding
+ */
+ if (fwd_init() != 0)
+ return 3;
+
+ /*
+ * One or other of so, fwd_sock
+ * must be the highest fd on
+ * which to select.
+ */
+ if (so > max_fds)
+ max_fds = so;
+ if (fwd_sock > max_fds)
+ max_fds = fwd_sock;
+
+ /*
+ * Construct the root automount node
+ */
+ make_root_node();
+
+ /*
+ * Pick up the pieces from a previous run
+ * This is likely to (indirectly) need the rpc_fwd package
+ * so it *must* come after the call to fwd_init().
+ */
+ if (restart_existing_mounts)
+ restart();
+
+ /*
+ * Mount the top-level auto-mountpoints
+ */
+ nmount = mount_exported();
+
+ /*
+ * Now safe to tell parent that we are up and running
+ */
+ if (ppid)
+ kill(ppid, SIGQUIT);
+
+ if (nmount == 0) {
+ plog(XLOG_FATAL, "No work to do - quitting");
+ amd_state = Done;
+ return 0;
+ }
+
+#ifdef DEBUG
+ Debug(D_AMQ) {
+#endif /* DEBUG */
+ /*
+ * Register with amq
+ */
+ unregister_amq();
+
+ if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) {
+ plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)");
+ return 3;
+ }
+#ifdef DEBUG
+ }
+#endif /* DEBUG */
+
+ /*
+ * Start timeout_mp rolling
+ */
+ reschedule_timeout_mp();
+
+ /*
+ * Start the server
+ */
+ if (run_rpc() != Done) {
+ plog(XLOG_FATAL, "run_rpc failed");
+ amd_state = Done;
+ }
+
+ return 0;
+}
diff --git a/usr.sbin/amd/amd/nfs_subr.c b/usr.sbin/amd/amd/nfs_subr.c
new file mode 100644
index 0000000..297cf93
--- /dev/null
+++ b/usr.sbin/amd/amd/nfs_subr.c
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfs_subr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_subr.c,v 5.2.2.1 1992/02/09 15:08:53 jsp beta $
+ *
+ */
+
+#include "am.h"
+
+/*
+ * Convert from UN*X to NFS error code
+ */
+#ifdef NFS_ERROR_MAPPING
+NFS_ERROR_MAPPING
+#define nfs_error(e) \
+ ((nfsstat)((e) > NFS_LOMAP && (e) < NFS_HIMAP ? \
+ nfs_errormap[(e) - NFS_LOMAP] : (e)))
+#else
+#define nfs_error(e) ((nfsstat)(e))
+#endif /* NFS_ERROR_MAPPING */
+
+static char *do_readlink P((am_node *mp, int *error_return, struct attrstat **attrpp));
+static char *do_readlink(mp, error_return, attrpp)
+am_node *mp;
+int *error_return;
+struct attrstat **attrpp;
+{
+ char *ln;
+
+ /*
+ * If there is a readlink method, then use
+ * that, otherwise if a link exists use
+ * that, otherwise use the mount point.
+ */
+ if (mp->am_mnt->mf_ops->readlink) {
+ int retry = 0;
+ mp = (*mp->am_mnt->mf_ops->readlink)(mp, &retry);
+ if (mp == 0) {
+ *error_return = retry;
+ return 0;
+ }
+ /*reschedule_timeout_mp();*/
+ }
+ if (mp->am_link) {
+ ln = mp->am_link;
+ } else {
+ ln = mp->am_mnt->mf_mount;
+ }
+ if (attrpp)
+ *attrpp = &mp->am_attr;
+ return ln;
+}
+
+/*ARGSUSED*/
+voidp
+nfsproc_null_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_getattr_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "gettattr:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+#ifdef PRECISE_SYMLINKS
+getattr_retry:
+#endif /* PRECISE_SYMLINKS */
+
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ struct attrstat *attrp = &mp->am_attr;
+#ifdef PRECISE_SYMLINKS
+ if (mp->am_fattr.type == NFLNK) {
+ /*
+ * Make sure we can read the link,
+ * and then determine the length.
+ */
+ char *ln = do_readlink(mp, &retry, &attrp);
+ if (ln == 0)
+ goto getattr_retry;
+ }
+#endif /* PRECISE_SYMLINKS */
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tstat(%s), size = %d", mp->am_path, attrp->attrstat_u.attributes.size);
+#endif /* DEBUG */
+ mp->am_stats.s_getattr++;
+ return attrp;
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_setattr_2(argp, rqstp)
+struct sattrargs *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+
+ if (!fh_to_mp(&argp->file))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+voidp
+nfsproc_root_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp)&res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_lookup_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "lookup:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(&argp->dir, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ int error;
+ am_node *ap;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tlookuppn(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+ ap = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &error, VLOOK_CREATE);
+ if (ap == 0) {
+ if (error < 0) {
+#ifdef DEBUG
+ dlog("Not sending RPC reply");
+#endif /* DEBUG */
+ amd_stats.d_drops++;
+ return 0;
+ }
+ res.status = nfs_error(error);
+ } else {
+ mp_to_fh(ap, &res.diropres_u.diropres.file);
+ res.diropres_u.diropres.attributes = ap->am_fattr;
+ res.status = NFS_OK;
+ }
+ mp->am_stats.s_lookup++;
+ /*reschedule_timeout_mp();*/
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct readlinkres *
+nfsproc_readlink_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static struct readlinkres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "readlink:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+readlink_retry:
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ char *ln = do_readlink(mp, &retry, (struct attrstat **) 0);
+ if (ln == 0)
+ goto readlink_retry;
+ res.status = NFS_OK;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ if (ln)
+ plog(XLOG_DEBUG, "\treadlink(%s) = %s", mp->am_path, ln);
+#endif /* DEBUG */
+ res.readlinkres_u.data = ln;
+ mp->am_stats.s_readlink++;
+ }
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct readres *
+nfsproc_read_2(argp, rqstp)
+struct readargs *argp;
+struct svc_req *rqstp;
+{
+ static struct readres res;
+
+ bzero((char *)&res, sizeof(res));
+
+ res.status = nfs_error(EACCES);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+voidp
+nfsproc_writecache_2(argp, rqstp)
+voidp argp;
+struct svc_req *rqstp;
+{
+ static char res;
+
+ return (voidp) &res;
+}
+
+
+/*ARGSUSED*/
+struct attrstat *
+nfsproc_write_2(argp, rqstp)
+writeargs *argp;
+struct svc_req *rqstp;
+{
+ static struct attrstat res;
+
+ if (!fh_to_mp(&argp->file))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_create_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+
+ if (!fh_to_mp(&argp->where.dir))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+static nfsstat *
+unlink_or_rmdir(argp, rqstp, unlinkp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+int unlinkp;
+{
+ static nfsstat res;
+ int retry;
+ /*mntfs *mf;*/
+ am_node *mp = fh_to_mp3(&argp->dir, &retry, VLOOK_DELETE);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res = nfs_error(retry);
+ goto out;
+ }
+ /*mf = mp->am_mnt;*/
+ if (mp->am_fattr.type != NFDIR) {
+ res = nfs_error(ENOTDIR);
+ goto out;
+ }
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tremove(%s, %s)", mp->am_path, argp->name);
+#endif /* DEBUG */
+ mp = (*mp->am_mnt->mf_ops->lookuppn)(mp, argp->name, &retry, VLOOK_DELETE);
+ if (mp == 0) {
+ /*
+ * Ignore retries...
+ */
+ if (retry < 0)
+ retry = 0;
+ /*
+ * Usual NFS workaround...
+ */
+ else if (retry == ENOENT)
+ retry = 0;
+ res = nfs_error(retry);
+ } else {
+ forcibly_timeout_mp(mp);
+ res = NFS_OK;
+ }
+
+out:
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_remove_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ return unlink_or_rmdir(argp, rqstp, TRUE);
+}
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rename_2(argp, rqstp)
+renameargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from.dir) || !fh_to_mp(&argp->to.dir))
+ res = nfs_error(ESTALE);
+ /*
+ * If the kernel is doing clever things with referenced files
+ * then let it pretend...
+ */
+ else if (strncmp(argp->to.name, ".nfs", 4) == 0)
+ res = NFS_OK;
+ /*
+ * otherwise a failure
+ */
+ else
+ res = nfs_error(EROFS);
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_link_2(argp, rqstp)
+linkargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from) || !fh_to_mp(&argp->to.dir))
+ res = nfs_error(ESTALE);
+ else
+ res = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_symlink_2(argp, rqstp)
+symlinkargs *argp;
+struct svc_req *rqstp;
+{
+ static nfsstat res;
+ if (!fh_to_mp(&argp->from.dir))
+ res = nfs_error(ESTALE);
+ else
+ res = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+struct diropres *
+nfsproc_mkdir_2(argp, rqstp)
+createargs *argp;
+struct svc_req *rqstp;
+{
+ static struct diropres res;
+ if (!fh_to_mp(&argp->where.dir))
+ res.status = nfs_error(ESTALE);
+ else
+ res.status = nfs_error(EROFS);
+
+ return &res;
+}
+
+
+/*ARGSUSED*/
+nfsstat *
+nfsproc_rmdir_2(argp, rqstp)
+struct diropargs *argp;
+struct svc_req *rqstp;
+{
+ return unlink_or_rmdir(argp, rqstp, FALSE);
+}
+
+
+/*ARGSUSED*/
+struct readdirres *
+nfsproc_readdir_2(argp, rqstp)
+readdirargs *argp;
+struct svc_req *rqstp;
+{
+ static readdirres res;
+ static entry e_res[MAX_READDIR_ENTRIES];
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "readdir:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(&argp->dir, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\treaddir(%s)", mp->am_path);
+#endif /* DEBUG */
+ res.status = nfs_error((*mp->am_mnt->mf_ops->readdir)(mp, argp->cookie,
+ &res.readdirres_u.reply, e_res, argp->count));
+ mp->am_stats.s_readdir++;
+ }
+
+ return &res;
+}
+
+/*ARGSUSED*/
+struct statfsres *
+nfsproc_statfs_2(argp, rqstp)
+struct nfs_fh *argp;
+struct svc_req *rqstp;
+{
+ static statfsres res;
+ am_node *mp;
+ int retry;
+
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "statfs:");
+#endif /* DEBUG */
+
+ mp = fh_to_mp2(argp, &retry);
+ if (mp == 0) {
+ if (retry < 0)
+ return 0;
+ res.status = nfs_error(retry);
+ } else {
+ statfsokres *fp;
+#ifdef DEBUG
+ Debug(D_TRACE)
+ plog(XLOG_DEBUG, "\tstat_fs(%s)", mp->am_path);
+#endif /* DEBUG */
+ /*
+ * just return faked up file system information
+ */
+
+ fp = &res.statfsres_u.reply;
+
+ fp->tsize = 1024;
+ fp->bsize = 4096;
+#ifdef HAS_EMPTY_AUTOMOUNTS
+ fp->blocks = 0;
+#else
+ fp->blocks = 1;
+#endif
+ fp->bfree = 0;
+ fp->bavail = 0;
+
+ res.status = NFS_OK;
+ mp->am_stats.s_statfs++;
+ }
+
+ return &res;
+}
diff --git a/usr.sbin/amd/amd/nfsx_ops.c b/usr.sbin/amd/amd/nfsx_ops.c
new file mode 100644
index 0000000..ba18cdc
--- /dev/null
+++ b/usr.sbin/amd/amd/nfsx_ops.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfsx_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfsx_ops.c,v 5.2.2.3 1992/05/31 16:13:07 jsp Exp $
+ *
+ */
+
+#include "am.h"
+
+#ifdef HAS_NFSX
+
+/*
+ * NFS hierarchical mounts
+ *
+ * TODO: Re-implement.
+ */
+
+/*
+ * The rfs field contains a list of mounts to be done from
+ * the remote host.
+ */
+typedef struct nfsx_mnt {
+ mntfs *n_mnt;
+ int n_error;
+} nfsx_mnt;
+
+struct nfsx {
+ int nx_c; /* Number of elements in nx_v */
+ nfsx_mnt *nx_v; /* Underlying mounts */
+ nfsx_mnt *nx_try;
+};
+
+static int nfsx_fmount P((mntfs*));
+
+static char *nfsx_match(fo)
+am_opts *fo;
+{
+ char *xmtab;
+ char *ptr;
+ int len;
+
+ if (!fo->opt_rfs) {
+ plog(XLOG_USER, "nfsx: no remote filesystem specified");
+ return FALSE;
+ }
+ if (!fo->opt_rhost) {
+ plog(XLOG_USER, "nfsx: no remote host specified");
+ return FALSE;
+ }
+
+#ifdef notdef
+ /* fiddle sublink, must be last... */
+ if (fo->opt_sublink) {
+ plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink);
+ free((voidp) fo->opt_sublink);
+ fo->opt_sublink = 0;
+ }
+#endif
+
+ /* set default sublink */
+ if (fo->opt_sublink == 0) {
+ ptr = strchr(fo->opt_rfs, ',');
+ if (ptr && ptr != (fo->opt_rfs + 1))
+ fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
+ }
+
+ /*
+ * Remove trailing ",..." from ${fs}
+ * After deslashifying, overwrite the end of ${fs} with "/"
+ * to make sure it is unique.
+ */
+ if (ptr = strchr(fo->opt_fs, ','))
+ *ptr = '\0';
+ deslashify(fo->opt_fs);
+ /*
+ * Bump string length to allow trailing /
+ */
+ len = strlen(fo->opt_fs);
+ fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1);
+ ptr = fo->opt_fs + len;
+ /*
+ * Make unique...
+ */
+ *ptr++ = '/';
+ *ptr = '\0';
+
+ /*
+ * Determine magic cookie to put in mtab
+ */
+ xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs);
+#ifdef DEBUG
+ dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
+ fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
+#endif /* DEBUG */
+
+ return xmtab;
+}
+
+static void nfsx_prfree P((voidp vp));
+static void nfsx_prfree(vp)
+voidp vp;
+{
+ struct nfsx *nx = (struct nfsx *) vp;
+ int i;
+
+ for (i = 0; i < nx->nx_c; i++) {
+ mntfs *m = nx->nx_v[i].n_mnt;
+ if (m)
+ free_mntfs(m);
+ }
+
+ free((voidp) nx->nx_v);
+ free((voidp) nx);
+}
+
+static int nfsx_init(mf)
+mntfs *mf;
+{
+ /*
+ * mf_info has the form:
+ * host:/prefix/path,sub,sub,sub
+ */
+ int i;
+ int glob_error;
+ struct nfsx *nx;
+ int asked_for_wakeup = 0;
+
+ nx = (struct nfsx *) mf->mf_private;
+
+ if (nx == 0) {
+ char **ivec;
+ char *info = 0;
+ char *host;
+ char *pref;
+ int error = 0;
+
+ info = strdup(mf->mf_info);
+ host = strchr(info, ':');
+ if (!host) {
+ error = EINVAL;
+ goto errexit;
+ }
+
+ pref = host+1;
+ host = info;
+
+ /*
+ * Split the prefix off from the suffices
+ */
+ ivec = strsplit(pref, ',', '\'');
+
+ /*
+ * Count array size
+ */
+ for (i = 0; ivec[i]; i++)
+ ;
+
+ nx = ALLOC(nfsx);
+ mf->mf_private = (voidp) nx;
+ mf->mf_prfree = nfsx_prfree;
+
+ nx->nx_c = i - 1; /* i-1 because we don't want the prefix */
+ nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(nfsx_mnt));
+ { char *mp = 0;
+ char *xinfo = 0;
+ char *fs = mf->mf_fo->opt_fs;
+ char *rfs = 0;
+ for (i = 0; i < nx->nx_c; i++) {
+ char *path = ivec[i+1];
+ rfs = str3cat(rfs, pref, "/", path);
+ /*
+ * Determine the mount point.
+ * If this is the root, then don't remove
+ * the trailing slash to avoid mntfs name clashes.
+ */
+ mp = str3cat(mp, fs, "/", rfs);
+ normalize_slash(mp);
+ deslashify(mp);
+ /*
+ * Determine the mount info
+ */
+ xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
+ normalize_slash(xinfo);
+ if (pref[1] != '\0')
+ deslashify(xinfo);
+#ifdef DEBUG
+ dlog("nfsx: init mount for %s on %s", xinfo, mp);
+#endif
+ nx->nx_v[i].n_error = -1;
+ nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
+ }
+ if (rfs) free(rfs);
+ if (mp) free(mp);
+ if (xinfo) free(xinfo);
+ }
+
+ free((voidp) ivec);
+errexit:
+ if (info)
+ free(info);
+ if (error)
+ return error;
+ }
+
+ /*
+ * Iterate through the mntfs's and call
+ * the underlying init routine on each
+ */
+ glob_error = 0;
+ for (i = 0; i < nx->nx_c; i++) {
+ nfsx_mnt *n = &nx->nx_v[i];
+ mntfs *m = n->n_mnt;
+ int error = (*m->mf_ops->fs_init)(m);
+ /*
+ * If HARD_NFSX_ERRORS is defined, make any
+ * initialisation failure a hard error and
+ * fail the entire group. Otherwise only fail
+ * if none of the group is mountable (see nfsx_fmount).
+ */
+#ifdef HARD_NFSX_ERRORS
+ if (error > 0)
+ return error;
+#else
+ if (error > 0)
+ n->n_error = error;
+#endif
+ else if (error < 0) {
+ glob_error = -1;
+ if (!asked_for_wakeup) {
+ asked_for_wakeup = 1;
+ sched_task(wakeup_task, (voidp) mf, (voidp) m);
+ }
+ }
+ }
+
+ return glob_error;
+}
+
+static void nfsx_cont P((int rc, int term, voidp closure));
+static void nfsx_cont(rc, term, closure)
+int rc;
+int term;
+voidp closure;
+{
+ mntfs *mf = (mntfs *) closure;
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n = nx->nx_try;
+
+ n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
+ mf->mf_flags &= ~MFF_ERROR;
+
+ /*
+ * Wakeup anything waiting for this mount
+ */
+ wakeup((voidp) n->n_mnt);
+
+ if (rc || term) {
+ if (term) {
+ /*
+ * Not sure what to do for an error code.
+ */
+ plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
+ n->n_error = EIO;
+ } else {
+ /*
+ * Check for exit status
+ */
+ errno = rc; /* XXX */
+ plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount);
+ n->n_error = rc;
+ }
+ free_mntfs(n->n_mnt);
+ n->n_mnt = new_mntfs();
+ n->n_mnt->mf_error = n->n_error;
+ n->n_mnt->mf_flags |= MFF_ERROR;
+ } else {
+ /*
+ * The mount worked.
+ */
+ mf_mounted(n->n_mnt);
+ n->n_error = 0;
+ }
+
+ /*
+ * Do the remaining bits
+ */
+ if (nfsx_fmount(mf) >= 0) {
+ wakeup((voidp) mf);
+ mf->mf_flags &= ~MFF_MOUNTING;
+ mf_mounted(mf);
+ }
+}
+
+static int try_nfsx_mount P((voidp mv));
+static int try_nfsx_mount(mv)
+voidp mv;
+{
+ mntfs *mf = (mntfs *) mv;
+ int error;
+
+ mf->mf_flags |= MFF_MOUNTING;
+ error = (*mf->mf_ops->fmount_fs)(mf);
+ mf->mf_flags &= ~MFF_MOUNTING;
+ return error;
+}
+
+static int nfsx_remount P((mntfs *mf, int fg));
+static int nfsx_remount(mf, fg)
+mntfs *mf;
+int fg;
+{
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n;
+ int glob_error = -1;
+
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
+ int error = mkdirs(m->mf_mount, 0555);
+ if (!error)
+ m->mf_flags |= MFF_MKMNT;
+ }
+ }
+ }
+
+ /*
+ * Iterate through the mntfs's and mount each filesystem
+ * which is not yet mounted.
+ */
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ /*
+ * Check fmount entry pt. exists
+ * and then mount...
+ */
+ if (!m->mf_ops->fmount_fs) {
+ n->n_error = EINVAL;
+ } else {
+#ifdef DEBUG
+ dlog("calling underlying fmount on %s", m->mf_mount);
+#endif
+ if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
+ m->mf_flags |= MFF_MOUNTING; /* XXX */
+#ifdef DEBUG
+ dlog("backgrounding mount of \"%s\"", m->mf_info);
+#endif
+ nx->nx_try = n;
+ run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf);
+ n->n_error = -1;
+ return -1;
+ } else {
+#ifdef DEBUG
+ dlog("foreground mount of \"%s\" ...", mf->mf_info);
+#endif
+ n->n_error = (*m->mf_ops->fmount_fs)(m);
+ }
+ }
+#ifdef DEBUG
+ if (n->n_error > 0) {
+ errno = n->n_error; /* XXX */
+ dlog("underlying fmount of %s failed: %m", m->mf_mount);
+ }
+#endif
+ if (n->n_error == 0) {
+ glob_error = 0;
+ } else if (glob_error < 0) {
+ glob_error = n->n_error;
+ }
+ }
+ }
+
+ return glob_error < 0 ? 0 : glob_error;
+}
+
+static int nfsx_fmount P((mntfs *mf));
+static int nfsx_fmount(mf)
+mntfs *mf;
+{
+ return nfsx_remount(mf, FALSE);
+}
+
+/*
+ * Unmount an NFS hierarchy.
+ * Note that this is called in the foreground
+ * and so may hang under extremely rare conditions.
+ */
+static int nfsx_fumount(mf)
+mntfs *mf;
+{
+ struct nfsx *nx = (struct nfsx *) mf->mf_private;
+ nfsx_mnt *n;
+ int glob_error = 0;
+
+ /*
+ * Iterate in reverse through the mntfs's and unmount each filesystem
+ * which is mounted.
+ */
+ for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
+ mntfs *m = n->n_mnt;
+ /*
+ * If this node has not been messed with
+ * and there has been no error so far
+ * then try and unmount.
+ * If an error had occured then zero
+ * the error code so that the remount
+ * only tries to unmount those nodes
+ * which had been successfully unmounted.
+ */
+ if (n->n_error == 0) {
+#ifdef DEBUG
+ dlog("calling underlying fumount on %s", m->mf_mount);
+#endif
+ n->n_error = (*m->mf_ops->fumount_fs)(m);
+ if (n->n_error) {
+ glob_error = n->n_error;
+ n->n_error = 0;
+ } else {
+ /*
+ * Make sure remount gets this node
+ */
+ n->n_error = -1;
+ }
+ }
+ }
+
+ /*
+ * If any unmounts failed then remount the
+ * whole lot...
+ */
+ if (glob_error) {
+ glob_error = nfsx_remount(mf, TRUE);
+ if (glob_error) {
+ errno = glob_error; /* XXX */
+ plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount);
+ }
+ glob_error = EBUSY;
+ } else {
+ /*
+ * Remove all the mount points
+ */
+ for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
+ mntfs *m = n->n_mnt;
+ if (n->n_error < 0) {
+ if (m->mf_ops->fs_flags & FS_MKMNT) {
+ (void) rmdirs(m->mf_mount);
+ m->mf_flags &= ~MFF_MKMNT;
+ }
+ }
+ free_mntfs(m);
+ n->n_mnt = 0;
+ n->n_error = -1;
+ }
+ }
+
+ return glob_error;
+}
+
+/*
+ * Ops structure
+ */
+am_ops nfsx_ops = {
+ "nfsx",
+ nfsx_match,
+ nfsx_init,
+ auto_fmount,
+ nfsx_fmount,
+ auto_fumount,
+ nfsx_fumount,
+ efs_lookuppn,
+ efs_readdir,
+ 0, /* nfsx_readlink */
+ 0, /* nfsx_mounted */
+ 0, /* nfsx_umounted */
+ find_nfs_srvr, /* XXX */
+ /*FS_UBACKGROUND|*/FS_AMQINFO
+};
+
+#endif /* HAS_NFSX */
diff --git a/usr.sbin/amd/amd/opts.c b/usr.sbin/amd/amd/opts.c
new file mode 100644
index 0000000..54c9675
--- /dev/null
+++ b/usr.sbin/amd/amd/opts.c
@@ -0,0 +1,835 @@
+/*-
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: opts.c,v 5.2.2.3 1992/05/31 16:34:13 jsp Exp $
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)opts.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include "am.h"
+
+extern char *getenv P((const char *));
+
+/*
+ * static copy of the options with
+ * which to play
+ */
+static struct am_opts fs_static;
+
+static char *opt_host = hostname;
+static char *opt_hostd = hostd;
+static char nullstr[] = "";
+static char *opt_key = nullstr;
+static char *opt_map = nullstr;
+static char *opt_path = nullstr;
+
+static char *vars[8];
+
+/*
+ * Length of longest option name
+ */
+#define NLEN 16 /* conservative */
+#define S(x) (x) , (sizeof(x)-1)
+static struct opt {
+ char *name; /* Name of the option */
+ int nlen; /* Length of option name */
+ char **optp; /* Pointer to option value string */
+ char **sel_p; /* Pointer to selector value string */
+} opt_fields[] = {
+ /* Options in something corresponding to frequency of use */
+ { S("opts"), &fs_static.opt_opts, 0 },
+ { S("host"), 0, &opt_host },
+ { S("hostd"), 0, &opt_hostd },
+ { S("type"), &fs_static.opt_type, 0 },
+ { S("rhost"), &fs_static.opt_rhost, 0 },
+ { S("rfs"), &fs_static.opt_rfs, 0 },
+ { S("fs"), &fs_static.opt_fs, 0 },
+ { S("key"), 0, &opt_key },
+ { S("map"), 0, &opt_map },
+ { S("sublink"), &fs_static.opt_sublink, 0 },
+ { S("arch"), 0, &arch },
+ { S("dev"), &fs_static.opt_dev, 0 },
+ { S("pref"), &fs_static.opt_pref, 0 },
+ { S("path"), 0, &opt_path },
+ { S("autodir"), 0, &auto_dir },
+ { S("delay"), &fs_static.opt_delay, 0 },
+ { S("domain"), 0, &hostdomain },
+ { S("karch"), 0, &karch },
+ { S("cluster"), 0, &cluster },
+ { S("wire"), 0, &wire },
+ { S("byte"), 0, &endian },
+ { S("os"), 0, &op_sys },
+ { S("remopts"), &fs_static.opt_remopts, 0 },
+ { S("mount"), &fs_static.opt_mount, 0 },
+ { S("unmount"), &fs_static.opt_unmount, 0 },
+ { S("cache"), &fs_static.opt_cache, 0 },
+ { S("user"), &fs_static.opt_user, 0 },
+ { S("group"), &fs_static.opt_group, 0 },
+ { S("var0"), &vars[0], 0 },
+ { S("var1"), &vars[1], 0 },
+ { S("var2"), &vars[2], 0 },
+ { S("var3"), &vars[3], 0 },
+ { S("var4"), &vars[4], 0 },
+ { S("var5"), &vars[5], 0 },
+ { S("var6"), &vars[6], 0 },
+ { S("var7"), &vars[7], 0 },
+ { 0, 0, 0, 0 },
+};
+
+typedef struct opt_apply opt_apply;
+struct opt_apply {
+ char **opt;
+ char *val;
+};
+
+/*
+ * Specially expand the remote host name first
+ */
+static opt_apply rhost_expansion[] = {
+ { &fs_static.opt_rhost, "${host}" },
+ { 0, 0 },
+};
+/*
+ * List of options which need to be expanded
+ * Note that this the order here _may_ be important.
+ */
+static opt_apply expansions[] = {
+/* { &fs_static.opt_dir, 0 }, */
+ { &fs_static.opt_sublink, 0 },
+ { &fs_static.opt_rfs, "${path}" },
+ { &fs_static.opt_fs, "${autodir}/${rhost}${rfs}" },
+ { &fs_static.opt_opts, "rw" },
+ { &fs_static.opt_remopts, "${opts}" },
+ { &fs_static.opt_mount, 0 },
+ { &fs_static.opt_unmount, 0 },
+ { 0, 0 },
+};
+
+/*
+ * List of options which need to be free'ed before re-use
+ */
+static opt_apply to_free[] = {
+ { &fs_static.fs_glob, 0 },
+ { &fs_static.fs_local, 0 },
+ { &fs_static.fs_mtab, 0 },
+/* { &fs_static.opt_dir, 0 }, */
+ { &fs_static.opt_sublink, 0 },
+ { &fs_static.opt_rfs, 0 },
+ { &fs_static.opt_fs, 0 },
+ { &fs_static.opt_rhost, 0 },
+ { &fs_static.opt_opts, 0 },
+ { &fs_static.opt_remopts, 0 },
+ { &fs_static.opt_mount, 0 },
+ { &fs_static.opt_unmount, 0 },
+ { &vars[0], 0 },
+ { &vars[1], 0 },
+ { &vars[2], 0 },
+ { &vars[3], 0 },
+ { &vars[4], 0 },
+ { &vars[5], 0 },
+ { &vars[6], 0 },
+ { &vars[7], 0 },
+ { 0, 0 },
+};
+
+/*
+ * Skip to next option in the string
+ */
+static char *opt P((char**));
+static char *opt(p)
+char **p;
+{
+ char *cp = *p;
+ char *dp = cp;
+ char *s = cp;
+
+top:
+ while (*cp && *cp != ';') {
+ if (*cp == '\"') {
+ /*
+ * Skip past string
+ */
+ cp++;
+ while (*cp && *cp != '\"')
+ *dp++ = *cp++;
+ if (*cp)
+ cp++;
+ } else {
+ *dp++ = *cp++;
+ }
+ }
+
+ /*
+ * Skip past any remaining ';'s
+ */
+ while (*cp == ';')
+ cp++;
+
+ /*
+ * If we have a zero length string
+ * and there are more fields, then
+ * parse the next one. This allows
+ * sequences of empty fields.
+ */
+ if (*cp && dp == s)
+ goto top;
+
+ *dp = '\0';
+
+ *p = cp;
+ return s;
+}
+
+static int eval_opts P((char*, char*));
+static int eval_opts(opts, mapkey)
+char *opts;
+char *mapkey;
+{
+ /*
+ * Fill in the global structure fs_static by
+ * cracking the string opts. opts may be
+ * scribbled on at will.
+ */
+ char *o = opts;
+ char *f;
+
+ /*
+ * For each user-specified option
+ */
+ while (*(f = opt(&o))) {
+ struct opt *op;
+ enum vs_opt { OldSyn, SelEQ, SelNE, VarAss } vs_opt;
+ char *eq = strchr(f, '=');
+ char *opt;
+ if (!eq || eq[1] == '\0' || eq == f) {
+ /*
+ * No value, just continue
+ */
+ plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f);
+ continue;
+ }
+
+ /*
+ * Check what type of operation is happening
+ * !=, =! is SelNE
+ * == is SelEQ
+ * := is VarAss
+ * = is OldSyn (either SelEQ or VarAss)
+ */
+ if (eq[-1] == '!') { /* != */
+ vs_opt = SelNE;
+ eq[-1] = '\0';
+ opt = eq + 1;
+ } else if (eq[-1] == ':') { /* := */
+ vs_opt = VarAss;
+ eq[-1] = '\0';
+ opt = eq + 1;
+ } else if (eq[1] == '=') { /* == */
+ vs_opt = SelEQ;
+ eq[0] = '\0';
+ opt = eq + 2;
+ } else if (eq[1] == '!') { /* =! */
+ vs_opt = SelNE;
+ eq[0] = '\0';
+ opt = eq + 2;
+ } else { /* = */
+ vs_opt = OldSyn;
+ eq[0] = '\0';
+ opt = eq + 1;
+ }
+
+ /*
+ * For each recognised option
+ */
+ for (op = opt_fields; op->name; op++) {
+ /*
+ * Check whether they match
+ */
+ if (FSTREQ(op->name, f)) {
+ switch (vs_opt) {
+#if AMD_COMPAT <= 5000108
+ case OldSyn:
+ plog(XLOG_WARNING, "key %s: Old syntax selector found: %s=%s", mapkey, f, opt);
+ if (!op->sel_p) {
+ *op->optp = opt;
+ break;
+ }
+ /* fall through ... */
+#endif /* 5000108 */
+ case SelEQ:
+ case SelNE:
+ if (op->sel_p && (STREQ(*op->sel_p, opt) == (vs_opt == SelNE))) {
+ plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s",
+ mapkey,
+ op->name,
+ *op->sel_p,
+ vs_opt == SelNE ? "not " : "",
+ opt);
+ return 0;
+ }
+ break;
+
+ case VarAss:
+ if (op->sel_p) {
+ plog(XLOG_USER, "key %s: Can't assign to a selector (%s)", mapkey, op->name);
+ return 0;
+ }
+ *op->optp = opt;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (!op->name)
+ plog(XLOG_USER, "key %s: Unrecognised key/option \"%s\"", mapkey, f);
+ }
+
+ return 1;
+}
+
+/*
+ * Free an option
+ */
+static void free_op P((opt_apply*, int));
+/*ARGSUSED*/
+static void free_op(p, b)
+opt_apply *p;
+int b;
+{
+ if (*p->opt) {
+ free(*p->opt);
+ *p->opt = 0;
+ }
+}
+
+/*
+ * Normalize slashes in the string.
+ */
+void normalize_slash P((char *p));
+void normalize_slash(p)
+char *p;
+{
+ char *f = strchr(p, '/');
+ char *f0 = f;
+ if (f) {
+ char *t = f;
+ do {
+ /* assert(*f == '/'); */
+ if (f == f0 && f[0] == '/' && f[1] == '/') {
+ /* copy double slash iff first */
+ *t++ = *f++;
+ *t++ = *f++;
+ } else {
+ /* copy a single / across */
+ *t++ = *f++;
+ }
+
+ /* assert(f[-1] == '/'); */
+ /* skip past more /'s */
+ while (*f == '/')
+ f++;
+
+ /* assert(*f != '/'); */
+ /* keep copying up to next / */
+ while (*f && *f != '/') {
+ *t++ = *f++;
+ }
+
+ /* assert(*f == 0 || *f == '/'); */
+
+ } while (*f);
+ *t = 0; /* derived from fix by Steven Glassman */
+ }
+}
+
+/*
+ * Macro-expand an option. Note that this does not
+ * handle recursive expansions. They will go badly wrong.
+ * If sel is true then old expand selectors, otherwise
+ * don't expand selectors.
+ */
+static void expand_op P((opt_apply*, int));
+static void expand_op(p, sel_p)
+opt_apply *p;
+int sel_p;
+{
+/*
+ * The BUFSPACE macros checks that there is enough space
+ * left in the expansion buffer. If there isn't then we
+ * give up completely. This is done to avoid crashing the
+ * automounter itself (which would be a bad thing to do).
+ */
+#define BUFSPACE(ep, len) (((ep) + (len)) < expbuf+MAXPATHLEN)
+static char expand_error[] = "No space to expand \"%s\"";
+
+ char expbuf[MAXPATHLEN+1];
+ char nbuf[NLEN+1];
+ char *ep = expbuf;
+ char *cp = *p->opt;
+ char *dp;
+#ifdef DEBUG
+ char *cp_orig = *p->opt;
+#endif /* DEBUG */
+ struct opt *op;
+
+ while (dp = strchr(cp, '$')) {
+ char ch;
+ /*
+ * First copy up to the $
+ */
+ { int len = dp - cp;
+ if (BUFSPACE(ep, len)) {
+ strncpy(ep, cp, len);
+ ep += len;
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ }
+ cp = dp + 1;
+ ch = *cp++;
+ if (ch == '$') {
+ if (BUFSPACE(ep, 1)) {
+ *ep++ = '$';
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ } else if (ch == '{') {
+ /* Expansion... */
+ enum { E_All, E_Dir, E_File, E_Domain, E_Host } todo;
+ /*
+ * Find closing brace
+ */
+ char *br_p = strchr(cp, '}');
+ int len;
+ /*
+ * Check we found it
+ */
+ if (!br_p) {
+ /*
+ * Just give up
+ */
+ plog(XLOG_USER, "No closing '}' in \"%s\"", *p->opt);
+ goto out;
+ }
+ len = br_p - cp;
+ /*
+ * Figure out which part of the variable to grab.
+ */
+ if (*cp == '/') {
+ /*
+ * Just take the last component
+ */
+ todo = E_File;
+ cp++;
+ --len;
+ } else if (br_p[-1] == '/') {
+ /*
+ * Take all but the last component
+ */
+ todo = E_Dir;
+ --len;
+ } else if (*cp == '.') {
+ /*
+ * Take domain name
+ */
+ todo = E_Domain;
+ cp++;
+ --len;
+ } else if (br_p[-1] == '.') {
+ /*
+ * Take host name
+ */
+ todo = E_Host;
+ --len;
+ } else {
+ /*
+ * Take the whole lot
+ */
+ todo = E_All;
+ }
+ /*
+ * Truncate if too long. Since it won't
+ * match anyway it doesn't matter that
+ * it has been cut short.
+ */
+ if (len > NLEN)
+ len = NLEN;
+ /*
+ * Put the string into another buffer so
+ * we can do comparisons.
+ */
+ strncpy(nbuf, cp, len);
+ nbuf[len] = '\0';
+ /*
+ * Advance cp
+ */
+ cp = br_p + 1;
+ /*
+ * Search the option array
+ */
+ for (op = opt_fields; op->name; op++) {
+ /*
+ * Check for match
+ */
+ if (len == op->nlen && STREQ(op->name, nbuf)) {
+ char xbuf[NLEN+3];
+ char *val;
+ /*
+ * Found expansion. Copy
+ * the correct value field.
+ */
+ if (!(!op->sel_p == !sel_p)) {
+ /*
+ * Copy the string across unexpanded
+ */
+ sprintf(xbuf, "${%s%s%s}",
+ todo == E_File ? "/" :
+ todo == E_Domain ? "." : "",
+ nbuf,
+ todo == E_Dir ? "/" :
+ todo == E_Host ? "." : "");
+ val = xbuf;
+ /*
+ * Make sure expansion doesn't
+ * munge the value!
+ */
+ todo = E_All;
+ } else if (op->sel_p) {
+ val = *op->sel_p;
+ } else {
+ val = *op->optp;
+ }
+ if (val) {
+ /*
+ * Do expansion:
+ * ${/var} means take just the last part
+ * ${var/} means take all but the last part
+ * ${.var} means take all but first part
+ * ${var.} means take just the first part
+ * ${var} means take the whole lot
+ */
+ int vlen = strlen(val);
+ char *vptr = val;
+ switch (todo) {
+ case E_Dir:
+ vptr = strrchr(val, '/');
+ if (vptr)
+ vlen = vptr - val;
+ vptr = val;
+ break;
+ case E_File:
+ vptr = strrchr(val, '/');
+ if (vptr) {
+ vptr++;
+ vlen = strlen(vptr);
+ } else
+ vptr = val;
+ break;
+ case E_Domain:
+ vptr = strchr(val, '.');
+ if (vptr) {
+ vptr++;
+ vlen = strlen(vptr);
+ } else {
+ vptr = "";
+ vlen = 0;
+ }
+ break;
+ case E_Host:
+ vptr = strchr(val, '.');
+ if (vptr)
+ vlen = vptr - val;
+ vptr = val;
+ break;
+ case E_All:
+ break;
+ }
+#ifdef DEBUG
+ /*dlog("Expanding \"%s\" to \"%s\"", nbuf, val);*/
+#endif /* DEBUG */
+ if (BUFSPACE(ep, vlen)) {
+ strcpy(ep, vptr);
+ ep += vlen;
+ } else {
+ plog(XLOG_ERROR, expand_error, *p->opt);
+ goto out;
+ }
+ }
+ /*
+ * Done with this variable
+ */
+ break;
+ }
+ }
+ /*
+ * Check that the search was succesful
+ */
+ 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 0000000..314f62b
--- /dev/null
+++ b/usr.sbin/amd/amd/pfs_ops.c
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ * @(#)pfs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: pfs_ops.c,v 5.2.2.1 1992/02/09 15:08:56 jsp beta $
+ *
+ */
+
+#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 0000000..52a9c87
--- /dev/null
+++ b/usr.sbin/amd/amd/restart.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: restart.c,v 5.2.2.1 1992/02/09 15:08:59 jsp beta $
+ *
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)restart.c 8.1 (Berkeley) 6/6/93";
+#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 0000000..aaf1e0a
--- /dev/null
+++ b/usr.sbin/amd/amd/rpc_fwd.c
@@ -0,0 +1,430 @@
+/*
+ * 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.
+ *
+ * @(#)rpc_fwd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: rpc_fwd.c,v 5.2.2.1 1992/02/09 15:09:01 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..cd12e3b
--- /dev/null
+++ b/usr.sbin/amd/amd/sched.c
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ *
+ * @(#)sched.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: sched.c,v 5.2.2.1 1992/02/09 15:09:02 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..c1b1eba
--- /dev/null
+++ b/usr.sbin/amd/amd/sfs_ops.c
@@ -0,0 +1,208 @@
+/*
+ * 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.
+ *
+ * @(#)sfs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: sfs_ops.c,v 5.2.2.1 1992/02/09 15:09:04 jsp beta $
+ *
+ */
+
+#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 0000000..0440777
--- /dev/null
+++ b/usr.sbin/amd/amd/srvr_afs.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.
+ *
+ * @(#)srvr_afs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: srvr_afs.c,v 5.2.2.1 1992/02/09 15:09:05 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..4987c95
--- /dev/null
+++ b/usr.sbin/amd/amd/srvr_nfs.c
@@ -0,0 +1,719 @@
+/*
+ * 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.
+ *
+ * @(#)srvr_nfs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: srvr_nfs.c,v 5.2.2.1 1992/02/09 15:09:06 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..fd81c37
--- /dev/null
+++ b/usr.sbin/amd/amd/ufs_ops.c
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ *
+ * @(#)ufs_ops.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: ufs_ops.c,v 5.2.2.1 1992/02/09 15:09:08 jsp beta $
+ *
+ */
+
+#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.
+ */
+#ifdef M_NEWTYPE
+ char *type = MOUNT_TYPE_UFS;
+#else
+ int type = MOUNT_TYPE_UFS;
+#endif /* M_NEWTYPE */
+
+ 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 0000000..2c3e73d
--- /dev/null
+++ b/usr.sbin/amd/amd/umount_fs.c
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ *
+ * @(#)umount_fs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: umount_fs.c,v 5.2.2.1 1992/02/09 15:09:10 jsp beta $
+ *
+ */
+
+#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 0000000..8503cc8
--- /dev/null
+++ b/usr.sbin/amd/amd/util.c
@@ -0,0 +1,648 @@
+/*
+ * 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.
+ *
+ * @(#)util.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: util.c,v 5.2.2.2 1992/03/07 17:52:06 jsp 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 0000000..ea6d3da
--- /dev/null
+++ b/usr.sbin/amd/amd/wire.c
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ *
+ * @(#)wire.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wire.c,v 5.2.2.1 1992/02/09 15:09:15 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..8af6951
--- /dev/null
+++ b/usr.sbin/amd/amd/xutil.c
@@ -0,0 +1,491 @@
+/*
+ * 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.
+ *
+ * @(#)xutil.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: xutil.c,v 5.2.2.3 1992/03/07 10:36:09 jsp 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 0000000..f0618ae
--- /dev/null
+++ b/usr.sbin/amd/amq/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG = amq
+MAN8 = amq.8
+SRCS = amq.c amq_clnt.c amq_xdr.c misc_rpc.c
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-DARCH_REP=\"${MACHINE}\"
+CFLAGS+=-DOS_REP=\"bsd44\"
+CFLAGS+=-DOS_HDR=\"os-bsd44.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 0000000..5485925
--- /dev/null
+++ b/usr.sbin/amd/amq/amq.8
@@ -0,0 +1,130 @@
+.\"
+.\" 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.
+.\"
+.\" @(#)amq.8 8.3 (Berkeley) 4/18/94
+.\"
+.\" $Id: amq.8,v 5.2.2.1 1992/02/09 15:11:41 jsp beta $
+.\"
+.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 0000000..d3749bc
--- /dev/null
+++ b/usr.sbin/amd/amq/amq.c
@@ -0,0 +1,666 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq.c 8.1 (Berkeley) 6/7/93
+ *
+ * $Id: amq.c,v 5.2.2.1 1992/02/09 15:09:16 jsp beta $
+ *
+ */
+
+/*
+ * 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 5.2.2.1 1992/02/09 15:09:16 jsp beta $";
+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 0000000..2851786
--- /dev/null
+++ b/usr.sbin/amd/config/Configure
@@ -0,0 +1,60 @@
+#!/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.
+#
+# @(#)Configure 8.1 (Berkeley) 6/6/93
+#
+# $Id: Configure,v 5.2.1.2 91/05/07 22:20:26 jsp Alpha $
+#
+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 0000000..c4bdd3a
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.aix3
@@ -0,0 +1,5 @@
+# @(#)Makefile.aix3 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.aix3,v 5.2.2.1 1992/02/09 15:10:06 jsp beta $
+#
+SYSLIB = -lbsd
diff --git a/usr.sbin/amd/config/Makefile.bsd44 b/usr.sbin/amd/config/Makefile.bsd44
new file mode 100644
index 0000000..a41ff2d
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.bsd44
@@ -0,0 +1,8 @@
+# @(#)Makefile.bsd44 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.bsd44,v 5.2.2.1 1992/02/09 15:10:12 jsp beta $
+#
+# 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 0000000..0c4d7be
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.config
@@ -0,0 +1,91 @@
+# @(#)Makefile.config 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.config,v 5.2.2.1 1992/02/09 15:11:17 jsp beta $
+#
+
+#
+# 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 0000000..dd92f9e
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.hpux
@@ -0,0 +1,13 @@
+# @(#)Makefile.hpux 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.hpux,v 5.2.2.1 1992/02/09 15:10:26 jsp beta $
+#
+# 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 0000000..e936b45
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix
@@ -0,0 +1,10 @@
+# @(#)Makefile.irix 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.irix,v 5.2.2.1 1992/02/09 15:10:31 jsp beta $
+#
+# 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 0000000..165e0e4
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix3
@@ -0,0 +1,13 @@
+# @(#)Makefile.irix3 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.irix3,v 5.2 1992/05/31 16:40:22 jsp 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 0000000..4480e93
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.irix4
@@ -0,0 +1,14 @@
+# @(#)Makefile.irix4 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.irix4,v 5.2 1992/05/31 16:40:22 jsp 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 0000000..0bcfff6
--- /dev/null
+++ b/usr.sbin/amd/config/Makefile.stellix
@@ -0,0 +1,10 @@
+# @(#)Makefile.stellix 8.1 (Berkeley) 6/6/93
+#
+# $Id: Makefile.stellix,v 5.2.2.1 1992/02/09 15:10:45 jsp beta $
+#
+# 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 0000000..36f8f1f
--- /dev/null
+++ b/usr.sbin/amd/config/RELEASE
@@ -0,0 +1 @@
+$Revision: 5.2.3.1 $ of $Date: 1993/06/01 11:43:31 $ bsd44
diff --git a/usr.sbin/amd/config/arch b/usr.sbin/amd/config/arch
new file mode 100644
index 0000000..71c9224
--- /dev/null
+++ b/usr.sbin/amd/config/arch
@@ -0,0 +1,126 @@
+#! /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.
+#
+# @(#)arch 8.1 (Berkeley) 6/6/93
+#
+# $Id: arch,v 5.2.2.2 1992/05/31 16:45:35 jsp 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 0000000..2c97d81
--- /dev/null
+++ b/usr.sbin/amd/config/misc-aix3.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-aix3.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc-aix3.h,v 5.2.2.1 1992/02/09 15:10:05 jsp beta $
+ *
+ */
+
+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 0000000..d808627
--- /dev/null
+++ b/usr.sbin/amd/config/misc-hpux.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * @(#)misc-hpux.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc-hpux.h,v 5.2.2.1 1992/02/09 15:10:24 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..f7d6682
--- /dev/null
+++ b/usr.sbin/amd/config/misc-irix.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-irix.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc-irix.h,v 5.2.2.1 1992/02/09 15:10:30 jsp beta $
+ *
+ */
+
+#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 0000000..46a498e
--- /dev/null
+++ b/usr.sbin/amd/config/misc-next.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-next.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc-next.h,v 5.2.2.1 1992/02/09 15:10:34 jsp beta $
+ *
+ */
+
+#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 0000000..275a853
--- /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.
+ *
+ * @(#)misc-stellix.h 8.1 (Berkeley) 6/6/93
+ *
+ */
+
+#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 0000000..640c5a7
--- /dev/null
+++ b/usr.sbin/amd/config/misc-ultrix.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)misc-ultrix.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: misc-ultrix.h,v 5.2.2.1 1992/02/09 15:10:49 jsp beta $
+ *
+ */
+
+#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 0000000..07d9e80
--- /dev/null
+++ b/usr.sbin/amd/config/mount_aix.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mount_aix.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount_aix.c,v 5.2.2.1 1992/02/09 15:10:08 jsp beta $
+ *
+ */
+
+
+/*
+ * 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 0000000..9926960
--- /dev/null
+++ b/usr.sbin/amd/config/mount_irix.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mount_irix.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount_irix.c,v 5.2.2.1 1992/02/09 15:10:32 jsp beta $
+ *
+ */
+
+
+/*
+ * 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 0000000..45703db
--- /dev/null
+++ b/usr.sbin/amd/config/mount_stellix.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mount_stellix.c 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * 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 0000000..78bf941
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_aix.c
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ *
+ * @(#)mtab_aix.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab_aix.c,v 5.2.2.1 1992/02/09 15:10:07 jsp beta $
+ *
+ */
+
+#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 0000000..1d81127
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_bsd.c
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ * @(#)mtab_bsd.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab_bsd.c,v 5.2.2.1 1992/02/09 15:10:13 jsp beta $
+ *
+ */
+
+#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);
+ 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;
+ }
+ 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 0000000..8101f71
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_file.c
@@ -0,0 +1,472 @@
+/*
+ * 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.
+ *
+ * @(#)mtab_file.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab_file.c,v 5.2.2.1 1992/02/09 15:10:42 jsp beta $
+ *
+ */
+
+#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 0000000..241ea88
--- /dev/null
+++ b/usr.sbin/amd/config/mtab_ultrix.c
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ * @(#)mtab_ultrix.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mtab_ultrix.c,v 5.2.2.1 1992/02/09 15:10:50 jsp beta $
+ *
+ */
+
+#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 0000000..a510966
--- /dev/null
+++ b/usr.sbin/amd/config/newvers.sh
@@ -0,0 +1,88 @@
+#!/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.
+#
+# @(#)newvers.sh 8.1 (Berkeley) 6/6/93
+#
+# $Id: newvers.sh,v 5.2.2.1 1992/02/09 15:11:19 jsp beta $
+#
+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 0000000..bcc44d5
--- /dev/null
+++ b/usr.sbin/amd/config/os-acis43.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * @(#)os-acis43.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-acis43.h,v 5.2.2.1 1992/02/09 15:10:02 jsp beta $
+ *
+ * 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 0000000..c70b159
--- /dev/null
+++ b/usr.sbin/amd/config/os-aix3.h
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ *
+ * @(#)os-aix3.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-aix3.h,v 5.2.2.2 1992/05/31 16:38:49 jsp 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 0000000..edd85a4
--- /dev/null
+++ b/usr.sbin/amd/config/os-aux.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ *
+ * @(#)os-aux.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-aux.h,v 5.2.2.1 1992/02/09 15:10:10 jsp beta $
+ *
+ * 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 0000000..837d596
--- /dev/null
+++ b/usr.sbin/amd/config/os-bsd44.h
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ *
+ * @(#)os-bsd44.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-bsd44.h,v 5.2.2.1 1992/02/09 15:10:11 jsp beta $
+ *
+ * 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.
+ */
+#undef HAS_NIS_MAPS
+
+/*
+ * 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"
+
+/*
+ * 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 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 0000000..4a130e0
--- /dev/null
+++ b/usr.sbin/amd/config/os-concentrix.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * @(#)os-concentrix.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-concentrix.h,v 5.2.2.1 1992/02/09 15:10:14 jsp beta $
+ *
+ * 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 0000000..ade6c4c
--- /dev/null
+++ b/usr.sbin/amd/config/os-convex.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.
+ *
+ * @(#)os-convex.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-convex.h,v 5.2.2.1 1992/02/09 15:10:16 jsp beta $
+ *
+ * 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 0000000..ce10ae2
--- /dev/null
+++ b/usr.sbin/amd/config/os-defaults.h
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ *
+ * @(#)os-defaults.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-defaults.h,v 5.2.2.1 1992/02/09 15:10:17 jsp beta $
+ *
+ * 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 0000000..98c81bf
--- /dev/null
+++ b/usr.sbin/amd/config/os-dgux.h
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ *
+ * @(#)os-dgux.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-dgux.h,v 5.2.2.1 1992/02/09 15:10:18 jsp beta $
+ *
+ * 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 0000000..8c69421
--- /dev/null
+++ b/usr.sbin/amd/config/os-fpx4.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ *
+ * @(#)os-fpx4.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-fpx4.h,v 5.2.2.2 1992/05/31 16:39:34 jsp 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 0000000..5b3fb30
--- /dev/null
+++ b/usr.sbin/amd/config/os-hcx.h
@@ -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.
+ *
+ * @(#)os-hcx.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-hcx.h,v 5.2.2.1 1992/02/09 15:10:20 jsp beta $
+ *
+ * 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 0000000..43d2d0b
--- /dev/null
+++ b/usr.sbin/amd/config/os-hlh42.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ *
+ * @(#)os-hlh42.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-hlh42.h,v 5.2.2.1 1992/02/09 15:10:22 jsp beta $
+ *
+ * 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 0000000..42b6b8b
--- /dev/null
+++ b/usr.sbin/amd/config/os-hpux.h
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ *
+ * @(#)os-hpux.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-hpux.h,v 5.2.2.1 1992/02/09 15:10:23 jsp beta $
+ *
+ * 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 0000000..1d854f7
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix.h
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ * @(#)os-irix.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-irix.h,v 5.2.2.1 1992/02/09 15:10:28 jsp beta $
+ *
+ * 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 0000000..867097d
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix3.h
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ *
+ * @(#)os-irix3.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-irix3.h,v 5.2 1992/05/31 16:40:22 jsp 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 0000000..ee2f8cb
--- /dev/null
+++ b/usr.sbin/amd/config/os-irix4.h
@@ -0,0 +1,150 @@
+/*
+ * 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.
+ *
+ * @(#)os-irix4.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-irix4.h,v 5.2 1992/05/31 16:40:22 jsp 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 0000000..c9b1cc2
--- /dev/null
+++ b/usr.sbin/amd/config/os-next.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.
+ *
+ * @(#)os-next.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-next.h,v 5.2.2.1 1992/02/09 15:10:33 jsp beta $
+ *
+ * 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 0000000..21b5fdd
--- /dev/null
+++ b/usr.sbin/amd/config/os-pyrOSx.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.
+ *
+ * @(#)os-pyrOSx.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-pyrOSx.h,v 5.2.2.1 1992/02/09 15:10:37 jsp beta $
+ *
+ * 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 0000000..cff7951
--- /dev/null
+++ b/usr.sbin/amd/config/os-riscix.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.
+ *
+ * @(#)os-riscix.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-riscix.h,v 5.2.2.1 1992/02/09 15:10:38 jsp beta $
+ *
+ * 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 0000000..15c632c
--- /dev/null
+++ b/usr.sbin/amd/config/os-sos3.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * @(#)os-sos3.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-sos3.h,v 5.2.2.1 1992/02/09 15:10:39 jsp beta $
+ *
+ * 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 0000000..3853a6c
--- /dev/null
+++ b/usr.sbin/amd/config/os-sos4.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.
+ *
+ * @(#)os-sos4.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-sos4.h,v 5.2.2.1 1992/02/09 15:10:41 jsp beta $
+ *
+ * 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 0000000..8c6290a
--- /dev/null
+++ b/usr.sbin/amd/config/os-stellix.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 1989 Jan-Simon Pendry
+ * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)os-stellix.h 8.1 (Berkeley) 6/6/93
+ *
+ * Amd (automounter) definitions for Stellix.
+ * From Stephen C. Pope <scp@acl.lanl.gov>
+ *
+ * $Id: os-stellix.h,v 5.2.2.1 1992/02/09 15:10:43 jsp beta $
+ */
+
+#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 0000000..4871d79
--- /dev/null
+++ b/usr.sbin/amd/config/os-type
@@ -0,0 +1,128 @@
+#!/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.
+#
+# @(#)os-type 8.1 (Berkeley) 6/6/93
+#
+# $Id: os-type,v 5.2.2.2 1992/05/31 16:45:46 jsp 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 0000000..aece171
--- /dev/null
+++ b/usr.sbin/amd/config/os-u2_2.h
@@ -0,0 +1,161 @@
+/*
+ * 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.
+ *
+ * @(#)os-u2_2.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-u2_2.h,v 5.2.2.1 1992/02/09 15:10:48 jsp beta $
+ *
+ * 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 0000000..08a4f36
--- /dev/null
+++ b/usr.sbin/amd/config/os-u3_0.h
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ *
+ * @(#)os-u3_0.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-u3_0.h,v 5.2.2.1 1992/02/09 15:10:52 jsp beta $
+ *
+ * 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 0000000..07c9833
--- /dev/null
+++ b/usr.sbin/amd/config/os-u4_0.h
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ *
+ * @(#)os-u4_0.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-u4_0.h,v 5.2.2.1 1992/02/09 15:10:53 jsp beta $
+ *
+ * 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 0000000..f8f039c
--- /dev/null
+++ b/usr.sbin/amd/config/os-u4_2.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.
+ *
+ * @(#)os-u4_2.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-u4_2.h,v 5.2.2.1 1992/02/09 15:10:54 jsp beta $
+ *
+ * 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 0000000..3e80872
--- /dev/null
+++ b/usr.sbin/amd/config/os-umax43.h
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ *
+ * @(#)os-umax43.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-umax43.h,v 5.2.2.1 1992/02/09 15:10:55 jsp beta $
+ *
+ * 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 0000000..eb1be04
--- /dev/null
+++ b/usr.sbin/amd/config/os-utek.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * @(#)os-utek.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-utek.h,v 5.2.2.1 1992/02/09 15:10:56 jsp beta $
+ *
+ * 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 0000000..29612c4
--- /dev/null
+++ b/usr.sbin/amd/config/os-utx32.h
@@ -0,0 +1,85 @@
+/* $Id: os-utx32.h,v 5.2.1.1 90/10/21 22:31:11 jsp Exp $ */
+
+/*
+ * 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.
+ *
+ * @(#)os-utx32.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * 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 0000000..e85cea2
--- /dev/null
+++ b/usr.sbin/amd/config/os-xinu43.h
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ *
+ * @(#)os-xinu43.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: os-xinu43.h,v 5.2.2.1 1992/02/09 15:10:58 jsp beta $
+ *
+ * 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 0000000..297de2b
--- /dev/null
+++ b/usr.sbin/amd/doc/Makefile
@@ -0,0 +1,53 @@
+#
+# $Id: Makefile,v 5.2 90/06/23 22:21:25 jsp Rel $
+#
+# 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.
+#
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+#
+
+PROG = amdref
+SRCS = amdref.texinfo
+
+${PROG}: amdref.dvi
+
+amdref.dvi: ${SRCS}
+ -tex amdref; tex amdref
+
+clean:
+ -rm -f amdref.aux amdref.cp amdref.dvi amdref.fn amdref.ky \
+ amdref.log amdref.pg amdref.toc amdref.tp amdref.vr
diff --git a/usr.sbin/amd/doc/amdref.cps b/usr.sbin/amd/doc/amdref.cps
new file mode 100644
index 0000000..a146372
--- /dev/null
+++ b/usr.sbin/amd/doc/amdref.cps
@@ -0,0 +1,381 @@
+\initial {/}
+\entry {/etc/amd.start}{40}
+\entry {/etc/passwd maps}{15}
+\entry {/etc/rc.local additions}{40}
+\entry {/vol}{70}
+\initial {A}
+\entry {Additions to /etc/rc.local}{40}
+\entry {Aliased hostnames}{27}
+\entry {Alternate locations}{7}
+\entry {Amd command line options}{25}
+\entry {Amq command}{40}
+\entry {arch, FSinfo host attribute}{50}
+\entry {arch, mount selector}{20}
+\entry {Architecture dependent volumes}{68}
+\entry {Architecture sharing}{68}
+\entry {Architecture specific mounts}{69}
+\entry {Atomic NFS mounts}{33}
+\entry {auto, filesystem type}{36}
+\entry {autodir, mount selector}{20}
+\entry {Automatic generation of user maps}{15}
+\entry {Automount directory}{25}
+\entry {Automount filesystem}{36}
+\entry {Automounter configuration maps}{12}
+\entry {Automounter fundamentals}{5}
+\initial {B}
+\entry {Background mounts}{7}
+\entry {Binding names to filesystems}{6}
+\entry {bootparams, FSinfo prefix}{59}
+\entry {Bug reports}{3}
+\entry {byte, mount selector}{20}
+\initial {C}
+\entry {Cache interval}{26}
+\entry {cache, mount option}{36}
+\entry {Catch-all mount point}{70}
+\entry {Changing the interval before a filesystem times out}{26}
+\entry {Cluster names}{30}
+\entry {cluster, FSinfo host attribute}{50}
+\entry {cluster, mount selector}{20}
+\entry {Command line options, Amd}{25}
+\entry {Command line options, FSinfo}{58}
+\entry {config, FSinfo host attribute}{49}
+\entry {Configuration map types}{12}
+\entry {Controlling Amd}{41}
+\entry {Creating a pid file}{27}
+\initial {D}
+\entry {Debug options}{30}
+\entry {Defining a host, FSinfo}{48}
+\entry {Defining an Amd mount map, FSinfo}{56}
+\entry {Defining host attributes, FSinfo}{48}
+\entry {delay, mount option}{21}
+\entry {Delaying mounts from specific locations}{21}
+\entry {Determining the map type}{12}
+\entry {dev, mount option}{34}
+\entry {Direct automount filesystem}{37}
+\entry {direct, filesystem type}{37}
+\entry {Discovering version information}{28}
+\entry {Discovering what is going on at run-time}{41}
+\entry {Disk filesystems}{34}
+\entry {Displaying the process id}{27}
+\entry {Domain name}{26}
+\entry {Domain stripping}{18}
+\entry {domain, mount selector}{20}
+\entry {Domainname operators}{18}
+\entry {dumpset, FSinfo filesystems option}{55}
+\entry {dumpset, FSinfo prefix}{59}
+\entry {Duplicated volumes}{6}
+\initial {E}
+\entry {Environment variables}{18}
+\entry {Error filesystem}{38}
+\entry {error, filesystem type}{38}
+\entry {Example of architecture specific mounts}{69}
+\entry {Example of mounting home directories}{66}
+\entry {export, FSinfo special fstype}{52}
+\entry {exportfs, FSinfo mount option}{54}
+\entry {exports, FSinfo prefix}{59}
+\initial {F}
+\entry {File map syntactic conventions}{12}
+\entry {File maps}{12}
+\entry {Fileserver}{5}
+\entry {Filesystem}{5}
+\entry {Filesystem info package}{46}
+\entry {Filesystem type; auto}{36}
+\entry {Filesystem type; direct}{37}
+\entry {Filesystem type; error}{38}
+\entry {Filesystem type; host}{32}
+\entry {Filesystem type; inherit}{39}
+\entry {Filesystem type; link}{35}
+\entry {Filesystem type; nfs}{31}
+\entry {Filesystem type; nfsx}{33}
+\entry {Filesystem type; program}{34}
+\entry {Filesystem type; root}{39}
+\entry {Filesystem type; toplvl}{38}
+\entry {Filesystem type; ufs}{34}
+\entry {Filesystem type; union}{38}
+\entry {Filesystem types}{31}
+\entry {Flat file maps}{12}
+\entry {Flushing the map cache}{43}
+\entry {Forcing filesystem to time out}{45}
+\entry {freq, FSinfo filesystems option}{53}
+\entry {fs, mount option}{21}
+\entry {FSinfo}{46}
+\entry {FSinfo arch host attribute}{50}
+\entry {FSinfo automount definitions}{56}
+\entry {FSinfo cluster host attribute}{50}
+\entry {FSinfo command line options}{58}
+\entry {FSinfo config host attribute}{49}
+\entry {FSinfo dumpset filesystems option}{55}
+\entry {FSinfo error messages}{61}
+\entry {FSinfo filesystems}{51}
+\entry {FSinfo freq filesystems option}{53}
+\entry {FSinfo fstype filesystems option}{52}
+\entry {FSinfo grammar}{47}
+\entry {FSinfo host attributes}{48}
+\entry {FSinfo host definitions}{48}
+\entry {FSinfo log filesystems option}{55}
+\entry {FSinfo mount filesystems option}{54}
+\entry {FSinfo opts filesystems option}{53}
+\entry {FSinfo os host attribute}{50}
+\entry {FSinfo overview}{46}
+\entry {FSinfo passno filesystems option}{53}
+\entry {FSinfo static mounts}{55}
+\entry {fstab, FSinfo prefix}{60}
+\entry {fstype, FSinfo filesystems option}{52}
+\initial {G}
+\entry {Generic volume name}{70}
+\entry {Global statistics}{44}
+\entry {Grammar, FSinfo}{47}
+\initial {H}
+\entry {Hesiod maps}{15}
+\entry {Home directories}{66}
+\entry {host, filesystem type}{32}
+\entry {host, mount selector}{20}
+\entry {hostd, mount selector}{20}
+\entry {Hostname normalisation}{27}
+\entry {hostname, FSinfo command line option}{60}
+\entry {How keys are looked up}{16}
+\entry {How locations are parsed}{17}
+\entry {How to access environment variables in maps}{18}
+\entry {How to discover your version of Amd}{28}
+\entry {How to mount a local disk}{34}
+\entry {How to mount a UFS filesystems}{34}
+\entry {How to mount all NFS exported filesystems}{32}
+\entry {How to mount an atomic group of NFS filesystems}{33}
+\entry {How to mount and NFS filesystem}{31}
+\entry {How to reference part of the local name space}{35}
+\entry {How to select log messages}{29}
+\entry {How to set default map parameters}{18}
+\entry {How to set map cache parameters}{36}
+\entry {How to start a direct automount point}{37}
+\entry {How to start an indirect automount point}{36}
+\entry {How variables are expanded}{18}
+\initial {I}
+\entry {inherit, filesystem type}{39}
+\entry {Inheritance filesystem}{39}
+\entry {Interval before a filesystem times out}{26}
+\entry {Introduction}{4}
+\initial {K}
+\entry {karch, mount selector}{20}
+\entry {Keep-alives}{8}
+\entry {Key lookup}{16}
+\entry {key, mount selector}{20}
+\initial {L}
+\entry {License Information}{2}
+\entry {link, filesystem type}{35}
+\entry {Listing currently mounted filesystems}{41}
+\entry {Location format}{17}
+\entry {Location lists}{7}
+\entry {Log filename}{27}
+\entry {Log message selection}{29}
+\entry {log, FSinfo filesystems option}{55}
+\entry {Looking up keys}{16}
+\initial {M}
+\entry {Machine architecture names}{11}
+\entry {Machine architectures supported by Amd}{11}
+\entry {Mailing list}{3}
+\entry {Map cache options}{36}
+\entry {Map cache synchronising}{36}
+\entry {Map cache types}{36}
+\entry {Map cache, flushing}{43}
+\entry {Map defaults}{18}
+\entry {Map entry format}{17}
+\entry {Map lookup}{16}
+\entry {Map options}{21}
+\entry {Map types}{12}
+\entry {map, mount selector}{20}
+\entry {maps, FSinfo command line option}{60}
+\entry {Mount a filesystem under program control}{34}
+\entry {Mount home directories}{66}
+\entry {Mount information}{12}
+\entry {Mount map types}{12}
+\entry {Mount maps}{12}
+\entry {Mount option; cache}{36}
+\entry {Mount option; delay}{21}
+\entry {Mount option; dev}{34}
+\entry {Mount option; fs}{21}
+\entry {Mount option; mount}{34}
+\entry {Mount option; opts}{22}
+\entry {Mount option; rfs}{31}
+\entry {Mount option; rhost}{31}
+\entry {Mount option; sublink}{23}
+\entry {Mount option; type}{24}
+\entry {Mount option; unmount}{34}
+\entry {Mount retries}{7}
+\entry {Mount selector; arch}{20}
+\entry {Mount selector; autodir}{20}
+\entry {Mount selector; byte}{20}
+\entry {Mount selector; cluster}{20}
+\entry {Mount selector; domain}{20}
+\entry {Mount selector; host}{20}
+\entry {Mount selector; hostd}{20}
+\entry {Mount selector; karch}{20}
+\entry {Mount selector; key}{20}
+\entry {Mount selector; map}{20}
+\entry {Mount selector; os}{20}
+\entry {Mount selector; path}{20}
+\entry {Mount selector; wire}{21}
+\entry {mount system call}{22}
+\entry {mount system call flags}{22}
+\entry {Mount types}{31}
+\entry {mount, FSinfo filesystems option}{54}
+\entry {mount, mount option}{34}
+\entry {Mounting a local disk}{34}
+\entry {Mounting a UFS filesystem}{34}
+\entry {Mounting a volume}{7}
+\entry {Mounting an atomic group of NFS filesystems}{33}
+\entry {Mounting an NFS filesystem}{31}
+\entry {Mounting entire export trees}{32}
+\entry {Mounting part of the local name space}{35}
+\entry {Mounting user filesystems}{65}
+\entry {Multiple-threaded server}{9}
+\initial {N}
+\entry {Namespace}{6}
+\entry {ndbm maps}{13}
+\entry {Network filesystem group}{33}
+\entry {Network host filesystem}{32}
+\entry {Network-wide naming}{6}
+\entry {NFS}{31}
+\entry {NFS ping}{8}
+\entry {nfs, filesystem type}{31}
+\entry {nfsx, filesystem type}{33}
+\entry {NIS (YP) domain name}{30}
+\entry {NIS (YP) maps}{14}
+\entry {Nodes generated on a restart}{39}
+\entry {Non-blocking operation}{9}
+\entry {Normalising hostnames}{27}
+\initial {O}
+\entry {Obtaining the source code}{3}
+\entry {Operating system names}{10}
+\entry {Operating systems supported by Amd}{10}
+\entry {Operational principles}{7}
+\entry {opts, FSinfo filesystems option}{53}
+\entry {opts, mount option}{22}
+\entry {os, FSinfo host attribute}{50}
+\entry {os, mount selector}{20}
+\entry {Overriding defaults on the command line}{25}
+\entry {Overriding the default mount point}{21}
+\entry {Overriding the local domain name}{26}
+\entry {Overriding the NIS (YP) domain name}{30}
+\initial {P}
+\entry {Passing parameters to the mount system call}{22}
+\entry {passno, FSinfo filesystems option}{53}
+\entry {Password file maps}{15}
+\entry {path, mount selector}{20}
+\entry {Pathname operators}{18}
+\entry {Picking up existing mounts}{28}
+\entry {pid file, creating with -p option}{27}
+\entry {Primary server}{21}
+\entry {Process id}{27}
+\entry {process id of Amd daemon}{27}
+\entry {Program filesystem}{34}
+\entry {program, filesystem type}{34}
+\initial {Q}
+\entry {Querying an alternate host}{43}
+\entry {quiet, FSinfo command line option}{61}
+\initial {R}
+\entry {Referencing part of the local name space}{35}
+\entry {Regular expressions in maps}{36}
+\entry {Replacement volumes}{6}
+\entry {Replicated volumes}{6}
+\entry {Resolving aliased hostnames}{27}
+\entry {Restarting existing mounts}{28}
+\entry {rfs, mount option}{31}
+\entry {rhost, mount option}{31}
+\entry {Root filesystem}{39}
+\entry {root, filesystem type}{39}
+\entry {RPC retries}{9}
+\entry {Run-time administration}{40}
+\entry {rwho servers}{69}
+\initial {S}
+\entry {Secondary server}{21}
+\entry {sel, FSinfo mount option}{54}
+\entry {Selecting specific log messages}{29}
+\entry {Selector; arch}{20}
+\entry {Selector; autodir}{20}
+\entry {Selector; byte}{20}
+\entry {Selector; cluster}{20}
+\entry {Selector; domain}{20}
+\entry {Selector; host}{20}
+\entry {Selector; hostd}{20}
+\entry {Selector; karch}{20}
+\entry {Selector; key}{20}
+\entry {Selector; map}{20}
+\entry {Selector; os}{20}
+\entry {Selector; path}{20}
+\entry {Selector; wire}{21}
+\entry {Selectors}{19}
+\entry {Server crashes}{8}
+\entry {Setting a delay on a mount location}{21}
+\entry {Setting Amd's RPC parameters}{28}
+\entry {Setting debug flags}{30}
+\entry {Setting default map parameters}{18}
+\entry {Setting map cache parameters}{36}
+\entry {Setting map options}{21}
+\entry {Setting system mount options}{22}
+\entry {Setting the cluster name}{30}
+\entry {Setting the default mount directory}{25}
+\entry {Setting the filesystem type option}{24}
+\entry {Setting the interval before a filesystem times out}{26}
+\entry {Setting the interval between unmount attempts}{28}
+\entry {Setting the Kernel architecture}{26}
+\entry {Setting the local domain name}{26}
+\entry {Setting the local mount point}{21}
+\entry {Setting the log file}{27}
+\entry {Setting the NIS (YP) domain name}{30}
+\entry {Setting the sublink option}{23}
+\entry {Sharing a fileserver between architectures}{68}
+\entry {SIGHUP signal}{36}
+\entry {SIGINT signal}{41}
+\entry {SIGTERM signal}{41}
+\entry {Source code distribution}{3}
+\entry {Starting Amd}{40}
+\entry {Statically mounts filesystems, FSinfo}{55}
+\entry {Statistics}{44}
+\entry {Stopping Amd}{41}
+\entry {Stripping the local domain name}{18}
+\entry {sublink}{5}
+\entry {sublink, mount option}{23}
+\entry {Supported machine architectures}{11}
+\entry {Supported operating systems}{10}
+\entry {Symbolic link filesystem}{35}
+\entry {symlink, link filesystem type}{35}
+\entry {Synchronising the map cache}{36}
+\entry {syslog}{27}
+\entry {syslog priorities}{29}
+\initial {T}
+\entry {The mount system call}{22}
+\entry {Top level filesystem}{38}
+\entry {toplvl, filesystem type}{38}
+\entry {type, mount option}{24}
+\entry {Types of configuration map}{12}
+\entry {Types of filesystem}{31}
+\entry {Types of mount map}{12}
+\initial {U}
+\entry {UFS}{34}
+\entry {ufs, filesystem type}{34}
+\entry {Union file maps}{16}
+\entry {Union filesystem}{38}
+\entry {union, filesystem type}{38}
+\entry {Unix filesystem}{34}
+\entry {Unix namespace}{6}
+\entry {unmount attempt backoff interval}{28}
+\entry {unmount, mount option}{34}
+\entry {Unmounting a filesystem}{45}
+\entry {User filesystems}{65}
+\entry {User maps, automatic generation}{15}
+\entry {Using FSinfo}{46}
+\entry {Using syslog to log errors}{27}
+\entry {Using the password file as a map}{15}
+\initial {V}
+\entry {Variable expansion}{18}
+\entry {verbose, FSinfo command line option}{61}
+\entry {Version information}{28}
+\entry {volname, FSinfo mount option}{54}
+\entry {Volume}{5}
+\entry {Volume binding}{6}
+\entry {Volume names}{6}
+\initial {W}
+\entry {Wildcards in maps}{16}
+\entry {wire, mount selector}{21}
+\initial {Y}
+\entry {YP domain name}{30}
diff --git a/usr.sbin/amd/doc/amdref.ps b/usr.sbin/amd/doc/amdref.ps
new file mode 100644
index 0000000..17e10f5
--- /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 0000000..4a6d8e9
--- /dev/null
+++ b/usr.sbin/amd/doc/amdref.texinfo
@@ -0,0 +1,4554 @@
+\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 @(#)amdref.texinfo 8.1 (Berkeley) 6/6/93
+@c
+@c $Id: amdref.texinfo,v 5.2.2.1 1992/02/09 15:11:50 jsp beta $
+@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 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 0000000..73528ed
--- /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 0000000..2ae9344
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/Makefile
@@ -0,0 +1,30 @@
+# @(#)Makefile 8.1 (Berkeley) 6/28/93
+
+PROG= fsinfo
+MAN8= 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-bsd44.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 0000000..ee4b4ee
--- /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 0000000..7d75db2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/csg_sun3
@@ -0,0 +1,18 @@
+// $Id$
+// 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 0000000..0ef23a5
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/csg_vax
@@ -0,0 +1,67 @@
+// $Id$
+// 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 0000000..0cacb20
--- /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 0000000..6a46ce8
--- /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 0000000..bda2fd8
--- /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 0000000..5284147
--- /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 0000000..31f1be0
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/flamingo.doc.ic.ac.uk
@@ -0,0 +1,104 @@
+// mkfsinfo for flamingo
+// $Id$
+
+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 0000000..e847c85
--- /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 0000000..8804c8e
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/gould.doc.ic.ac.uk
@@ -0,0 +1,477 @@
+// mkfsinfo for gould
+// $Id$
+
+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 0000000..aae6a5d
--- /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 0000000..c8fcb5d
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/ivax.doc.ic.ac.uk
@@ -0,0 +1,84 @@
+// $Id$
+// 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 0000000..dd9f0f7
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/obsidian.doc.ic.ac.uk
@@ -0,0 +1,28 @@
+// $Id$
+// 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 0000000..1ffd8d7
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/pelican.doc.ic.ac.uk
@@ -0,0 +1,208 @@
+// mkfsinfo for pelican
+// $Id$
+
+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 0000000..303d552
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/rvax.doc.ic.ac.uk
@@ -0,0 +1,66 @@
+// $Id$
+// 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 0000000..7877659
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/sky.doc.ic.ac.uk
@@ -0,0 +1,79 @@
+// $Id$
+// 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 0000000..aa99fbf
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/svax.doc.ic.ac.uk
@@ -0,0 +1,66 @@
+// $Id$
+// 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 0000000..1b10d84
--- /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 0000000..933d2f4
--- /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 0000000..ccef4d4
--- /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 0000000..9de9a9a
--- /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 0000000..7f268a0
--- /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 0000000..7b27f16
--- /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 0000000..0139279
--- /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 0000000..ff5016c
--- /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 0000000..2496cdb
--- /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 0000000..d6e7b9d
--- /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 0000000..a8439bb
--- /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 0000000..44e4956
--- /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 0000000..66a5051
--- /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 0000000..3246df3
--- /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 0000000..4ab7bd0
--- /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 0000000..11ef757
--- /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 0000000..fbdf879
--- /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 0000000..da9aba8
--- /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 0000000..b6fca77
--- /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 0000000..e40bd16
--- /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 0000000..cd97358
--- /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 0000000..3a8c7e2
--- /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 0000000..4c6ea76
--- /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 0000000..9df32a9
--- /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 0000000..e2b5e1f
--- /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 0000000..e82e815
--- /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 0000000..b09db9d
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/tsunfs.doc.ic.ac.uk
@@ -0,0 +1,211 @@
+// mkfsinfo for tsunfs
+// $Id$
+
+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 0000000..831053b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/conf/hosts/whoops.doc.ic.ac.uk
@@ -0,0 +1,21 @@
+// $Id$
+// 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 0000000..9dc83d9
--- /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 0000000..d436a49
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_analyze.c
@@ -0,0 +1,645 @@
+/*
+ * 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.
+ *
+ * @(#)fsi_analyze.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsi_analyze.c,v 5.2.2.1 1992/02/09 15:09:41 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..3fc10c4
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_data.h
@@ -0,0 +1,236 @@
+/*
+ * 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.
+ *
+ * @(#)fsi_data.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsi_data.h,v 5.2.2.1 1992/02/09 15:09:53 jsp beta $
+ *
+ */
+
+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 0000000..5067e79
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_dict.c
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ *
+ * @(#)fsi_dict.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsi_dict.c,v 5.2.2.1 1992/02/09 15:09:43 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..b4aa245
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_gram.y
@@ -0,0 +1,394 @@
+/*
+ * 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.
+ *
+ * @(#)fsi_gram.y 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsi_gram.y,v 5.2.2.1 1992/02/09 15:09:35 jsp beta $
+ *
+ */
+
+%{
+#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 0000000..46ec532
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_lex.l
@@ -0,0 +1,403 @@
+%{
+/*
+ * 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.
+ *
+ * @(#)fsi_lex.l 8.2 (Berkeley) 2/17/94
+ *
+ * $Id: fsi_lex.l,v 5.2.2.1 1992/02/09 15:09:36 jsp beta $
+ *
+ */
+
+/*
+ * 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 /lib/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 0000000..c0d8088
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsi_util.c
@@ -0,0 +1,573 @@
+/*
+ * 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.
+ *
+ * @(#)fsi_util.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsi_util.c,v 5.2.2.1 1992/02/09 15:09:39 jsp beta $
+ *
+ */
+
+#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: {
+ extern u_long inet_addr();
+ ep->e_inaddr.s_addr = inet_addr(v);
+ if (ep->e_inaddr.s_addr == (u_long) -1)
+ 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 0000000..34db7c2
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.8
@@ -0,0 +1,77 @@
+.\" 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.
+.\"
+.\" @(#)fsinfo.8 8.1 (Berkeley) 6/28/93
+.\"
+.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 0000000..a4b867b
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.c
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ *
+ * @(#)fsinfo.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsinfo.c,v 5.2.2.1 1992/02/09 15:09:33 jsp beta $
+ *
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * 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 0000000..0d07e21
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/fsinfo.h
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ *
+ * @(#)fsinfo.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fsinfo.h,v 5.2.2.1 1992/02/09 15:09:51 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..3e07965
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_atab.c
@@ -0,0 +1,284 @@
+/*
+ * 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.
+ *
+ * @(#)wr_atab.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wr_atab.c,v 5.2.2.1 1992/02/09 15:09:44 jsp beta $
+ *
+ */
+
+#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 0000000..9ef0fcd
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_bparam.c
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ *
+ * @(#)wr_bparam.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wr_bparam.c,v 5.2.2.1 1992/02/09 15:09:46 jsp beta $
+ *
+ */
+
+#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 0000000..d118feb
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_dumpset.c
@@ -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.
+ *
+ * @(#)wr_dumpset.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wr_dumpset.c,v 5.2.2.1 1992/02/09 15:09:47 jsp beta $
+ *
+ */
+
+#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 0000000..982b538f
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_exportfs.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ *
+ * @(#)wr_exportfs.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wr_exportfs.c,v 5.2.2.1 1992/02/09 15:09:48 jsp beta $
+ *
+ */
+
+#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 0000000..85d3687
--- /dev/null
+++ b/usr.sbin/amd/fsinfo/wr_fstab.c
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ *
+ * @(#)wr_fstab.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: wr_fstab.c,v 5.2.2.1 1992/02/09 15:09:49 jsp beta $
+ *
+ */
+
+#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 0000000..14a728d
--- /dev/null
+++ b/usr.sbin/amd/include/am.h
@@ -0,0 +1,567 @@
+/*
+ * 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.
+ *
+ * @(#)am.h 5.6 (Berkeley) 6/6/93
+ *
+ * $Id: am.h,v 5.2.2.1 1992/02/09 15:09:54 jsp beta $
+ *
+ */
+
+#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 0000000..09b77bf
--- /dev/null
+++ b/usr.sbin/amd/include/config.h
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ *
+ * @(#)config.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: config.h,v 5.2.2.1 1992/02/09 15:09:56 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..03493d2
--- /dev/null
+++ b/usr.sbin/amd/include/fstype.h
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ *
+ * @(#)fstype.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: fstype.h,v 5.2.2.1 1992/02/09 15:09:57 jsp beta $
+ *
+ */
+
+/*
+ * 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/re.h b/usr.sbin/amd/include/re.h
new file mode 100644
index 0000000..73d6bf4
--- /dev/null
+++ b/usr.sbin/amd/include/re.h
@@ -0,0 +1,21 @@
+/*
+ * Definitions etc. for regexp(3) routines.
+ *
+ * Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
+ * not the System V one.
+ */
+#define NSUBEXP 10
+typedef struct regexp {
+ char *startp[NSUBEXP];
+ char *endp[NSUBEXP];
+ char regstart; /* Internal use only. */
+ char reganch; /* Internal use only. */
+ char *regmust; /* Internal use only. */
+ int regmlen; /* Internal use only. */
+ char program[1]; /* Unwarranted chumminess with compiler. */
+} regexp;
+
+extern regexp *regcomp();
+extern int regexec();
+extern void regsub();
+extern void regerror();
diff --git a/usr.sbin/amd/include/remagic.h b/usr.sbin/amd/include/remagic.h
new file mode 100644
index 0000000..5acf447
--- /dev/null
+++ b/usr.sbin/amd/include/remagic.h
@@ -0,0 +1,5 @@
+/*
+ * The first byte of the regexp internal "program" is actually this magic
+ * number; the start node begins in the second byte.
+ */
+#define MAGIC 0234
diff --git a/usr.sbin/amd/include/uwait.h b/usr.sbin/amd/include/uwait.h
new file mode 100644
index 0000000..c3f8cbe
--- /dev/null
+++ b/usr.sbin/amd/include/uwait.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ *
+ * @(#)uwait.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: uwait.h,v 5.2.2.1 1992/02/09 15:10:01 jsp beta $
+ *
+ */
+
+#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 0000000..2f60dde
--- /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 0000000..ea2492b
--- /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 0000000..52c2a49
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/28/93
+
+PROG= mk-amd-map
+CFLAGS+=-I${.CURDIR}/../include
+CFLAGS+=-I${.CURDIR}/../rpcx
+CFLAGS+=-I${.CURDIR}/../config
+CFLAGS+=-DOS_HDR=\"os-bsd44.h\"
+MAN8= 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 0000000..20f3217
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/mk-amd-map.8
@@ -0,0 +1,59 @@
+.\" 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.
+.\"
+.\" @(#)mk-amd-map.8 8.1 (Berkeley) 6/28/93
+.\"
+.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 0000000..c2dfb71
--- /dev/null
+++ b/usr.sbin/amd/mk-amd-map/mk-amd-map.c
@@ -0,0 +1,384 @@
+/*
+ * 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.
+ *
+ * @(#)mk-amd-map.c 8.1 (Berkeley) 6/28/93
+ *
+ * $Id: mk-amd-map.c,v 5.2.2.1 1992/02/09 15:09:18 jsp beta $
+ */
+
+/*
+ * 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 5.2.2.1 1992/02/09 15:09:18 jsp beta $";
+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 0000000..7ec4d55
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq.h,v 5.2.2.1 1992/02/09 15:09:22 jsp beta $
+ *
+ */
+
+#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 0000000..d75805d
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq.x
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq.x 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq.x,v 5.2.2.1 1992/02/09 15:09:20 jsp beta $
+ *
+ */
+
+/*
+ * 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 0000000..5b70d11
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_clnt.c
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq_clnt.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq_clnt.c,v 5.2.2.1 1992/02/09 15:09:24 jsp beta $
+ *
+ */
+
+#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 0000000..0d3599f
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_svc.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq_svc.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq_svc.c,v 5.2.2.1 1992/02/09 15:09:26 jsp beta $
+ *
+ */
+
+#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 0000000..8a123a7
--- /dev/null
+++ b/usr.sbin/amd/rpcx/amq_xdr.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)amq_xdr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: amq_xdr.c,v 5.2.2.1 1992/02/09 15:09:23 jsp beta $
+ *
+ */
+
+#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, 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 0000000..d30b0c3
--- /dev/null
+++ b/usr.sbin/amd/rpcx/mount.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)mount.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount.h,v 5.2.2.1 1992/02/09 15:09:27 jsp beta $
+ *
+ */
+
+#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 0000000..f8d8f57
--- /dev/null
+++ b/usr.sbin/amd/rpcx/mount_xdr.c
@@ -0,0 +1,206 @@
+/*
+ * 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.
+ *
+ * @(#)mount_xdr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: mount_xdr.c,v 5.2.2.1 1992/02/09 15:09:28 jsp beta $
+ *
+ */
+
+#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 0000000..62a75f7
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)nfs_prot.h 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_prot.h,v 5.2.2.1 1992/02/09 15:09:29 jsp beta $
+ *
+ */
+
+#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 0000000..21e47e3
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot_svc.c
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ *
+ * @(#)nfs_prot_svc.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_prot_svc.c,v 5.2.2.1 1992/02/09 15:09:30 jsp beta $
+ *
+ */
+
+#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, &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 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 0000000..1786d01
--- /dev/null
+++ b/usr.sbin/amd/rpcx/nfs_prot_xdr.c
@@ -0,0 +1,627 @@
+/*
+ * 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.
+ *
+ * @(#)nfs_prot_xdr.c 8.1 (Berkeley) 6/6/93
+ *
+ * $Id: nfs_prot_xdr.c,v 5.2.2.1 1992/02/09 15:09:32 jsp beta $
+ *
+ */
+
+#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, &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, &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, &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, &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, &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, &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, &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 0000000..f2e96a6
--- /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 0000000..d35aaaa
--- /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 -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 5.2.2.2 1992/05/31 16:49:22 jsp Exp $
diff --git a/usr.sbin/amd/text/README b/usr.sbin/amd/text/README
new file mode 100644
index 0000000..01d3a8b
--- /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 5.2.2.1 1992/02/09 15:11:35 jsp beta $
diff --git a/usr.sbin/amd/text/amd.start.ex b/usr.sbin/amd/text/amd.start.ex
new file mode 100644
index 0000000..d7cdc1f
--- /dev/null
+++ b/usr.sbin/amd/text/amd.start.ex
@@ -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.
+#
+# @(#)amd.start.ex 8.1 (Berkeley) 6/6/93
+#
+# Start amd
+#
+# $Id: amd.start.ex,v 5.2.2.1 1992/02/09 15:11:32 jsp beta $
+#
+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 0000000..a26439f
--- /dev/null
+++ b/usr.sbin/arp/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.2 (Berkeley) 4/18/94
+
+PROG= arp
+MAN8= arp.8
+MAN4= arp.4
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/arp/arp.4 b/usr.sbin/arp/arp.4
new file mode 100644
index 0000000..0cd7161
--- /dev/null
+++ b/usr.sbin/arp/arp.4
@@ -0,0 +1,124 @@
+.\" 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.
+.\"
+.\" @(#)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 0000000..51fa68c
--- /dev/null
+++ b/usr.sbin/arp/arp.8
@@ -0,0 +1,122 @@
+.\" 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.
+.\"
+.\" @(#)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
+.Ar hostname
+.Nm arp
+.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 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 0000000..2182dc8
--- /dev/null
+++ b/usr.sbin/arp/arp.c
@@ -0,0 +1,514 @@
+/*
+ * 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[] = "@(#)arp.c 8.2 (Berkeley) 1/2/94";
+#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 <nlist.h>
+#include <stdio.h>
+#include <paths.h>
+
+extern int errno;
+static int pid;
+static int kflag;
+static int nflag;
+static int s = -1;
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int ch;
+
+ pid = getpid();
+ while ((ch = getopt(argc, argv, "ands")) != EOF)
+ switch((char)ch) {
+ case 'a':
+ dump(0);
+ exit(0);
+ case 'd':
+ if (argc < 3 || argc > 4)
+ usage();
+ delete(argv[2], argv[3]);
+ exit(0);
+ case 'n':
+ nflag = 1;
+ continue;
+ case 's':
+ if (argc < 4 || argc > 7)
+ usage();
+ exit(set(argc-2, &argv[2]) ? 1 : 0);
+ case '?':
+ default:
+ usage();
+ }
+ if (argc != 2)
+ usage();
+ get(argv[1]);
+ exit(0);
+}
+
+/*
+ * Process a file to set standard arp entries
+ */
+file(name)
+ char *name;
+{
+ FILE *fp;
+ int i, retval;
+ char line[100], arg[5][50], *args[5];
+
+ if ((fp = fopen(name, "r")) == NULL) {
+ fprintf(stderr, "arp: cannot open %s\n", name);
+ exit(1);
+ }
+ 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) {
+ fprintf(stderr, "arp: bad line: %s\n", line);
+ retval = 1;
+ continue;
+ }
+ if (set(i, args))
+ retval = 1;
+ }
+ fclose(fp);
+ return (retval);
+}
+
+getsocket() {
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("arp: socket");
+ exit(1);
+ }
+ }
+}
+
+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
+ */
+set(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct hostent *hp;
+ register struct sockaddr_inarp *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ u_char *ea;
+ char *host = argv[0], *eaddr = argv[1];
+
+ getsocket();
+ argc -= 2;
+ argv += 2;
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+ sin->sin_addr.s_addr = inet_addr(host);
+ if (sin->sin_addr.s_addr == -1) {
+ if (!(hp = gethostbyname(host))) {
+ fprintf(stderr, "arp: %s: ", host);
+ herror((char *)NULL);
+ return (1);
+ }
+ bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
+ sizeof sin->sin_addr);
+ }
+ 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;
+ 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) {
+ printf("%s: Sending trailers is no longer supported\n",
+ host);
+ }
+ argv++;
+ }
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ perror(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) {
+ printf("set: can only proxy for %s\n", host);
+ return (1);
+ }
+ if (sin_m.sin_other & SIN_PROXY) {
+ 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) {
+ 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
+ */
+get(host)
+ char *host;
+{
+ struct hostent *hp;
+ struct sockaddr_inarp *sin = &sin_m;
+ u_char *ea;
+
+ sin_m = blank_sin;
+ sin->sin_addr.s_addr = inet_addr(host);
+ if (sin->sin_addr.s_addr == -1) {
+ if (!(hp = gethostbyname(host))) {
+ fprintf(stderr, "arp: %s: ", host);
+ herror((char *)NULL);
+ exit(1);
+ }
+ bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
+ sizeof sin->sin_addr);
+ }
+ dump(sin->sin_addr.s_addr);
+ if (found_entry == 0) {
+ printf("%s (%s) -- no entry\n",
+ host, inet_ntoa(sin->sin_addr));
+ exit(1);
+ }
+}
+
+/*
+ * Delete an arp entry
+ */
+delete(host, info)
+ char *host;
+ char *info;
+{
+ struct hostent *hp;
+ register struct sockaddr_inarp *sin = &sin_m;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ struct sockaddr_dl *sdl;
+ u_char *ea;
+ char *eaddr;
+
+ if (info && strncmp(info, "pro", 3) )
+ export_only = 1;
+ getsocket();
+ sin_m = blank_sin;
+ sin->sin_addr.s_addr = inet_addr(host);
+ if (sin->sin_addr.s_addr == -1) {
+ if (!(hp = gethostbyname(host))) {
+ fprintf(stderr, "arp: %s: ", host);
+ herror((char *)NULL);
+ return (1);
+ }
+ bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
+ sizeof sin->sin_addr);
+ }
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ perror(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) {
+ fprintf(stderr, "delete: can't locate %s\n",host);
+ return (1);
+ } else {
+ sin_m.sin_other = SIN_PROXY;
+ goto tryagain;
+ }
+delete:
+ if (sdl->sdl_family != AF_LINK) {
+ printf("cannot locate %s\n", host);
+ return (1);
+ }
+ if (rtmsg(RTM_DELETE) == 0)
+ printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
+}
+
+/*
+ * Dump the entire arp table
+ */
+dump(addr)
+u_long addr;
+{
+ int mib[6];
+ size_t needed;
+ char *host, *malloc(), *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)
+ quit("route-sysctl-estimate");
+ if ((buf = malloc(needed)) == NULL)
+ quit("malloc");
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+ quit("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;
+ }
+ printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
+ if (sdl->sdl_alen)
+ ether_print(LLADDR(sdl));
+ else
+ printf("(incomplete)");
+ if (rtm->rtm_rmx.rmx_expire == 0)
+ printf(" permanent");
+ if (sin->sin_other & SIN_PROXY)
+ 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)
+ printf(" published");
+ if (sin->sin_len != 8)
+ printf("(wierd)");
+ }
+ printf("\n");
+ }
+}
+
+ether_print(cp)
+ u_char *cp;
+{
+ printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
+}
+
+ether_aton(a, n)
+ 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) {
+ fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
+ return (1);
+ }
+ for (i=0; i<6; i++)
+ n[i] = o[i];
+ return (0);
+}
+
+usage()
+{
+ printf("usage: arp hostname\n");
+ printf(" arp -a [kernel] [kernel_memory]\n");
+ printf(" arp -d hostname\n");
+ printf(" arp -s hostname ether_addr [temp] [pub]\n");
+ printf(" arp -f filename\n");
+ exit(1);
+}
+
+rtmsg(cmd)
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ if (cmd == RTM_DELETE)
+ goto doit;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ fprintf(stderr, "arp: internal wrong cmd\n");
+ exit(1);
+ 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)) { \
+ bcopy((char *)&s, cp, 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) {
+ perror("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)
+ (void) fprintf(stderr, "arp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+quit(msg)
+char *msg;
+{
+ fprintf(stderr, "%s\n", msg);
+ exit(1);
+}
diff --git a/usr.sbin/arp/arp4.4 b/usr.sbin/arp/arp4.4
new file mode 100644
index 0000000..0cd7161
--- /dev/null
+++ b/usr.sbin/arp/arp4.4
@@ -0,0 +1,124 @@
+.\" 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.
+.\"
+.\" @(#)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/bad144/Makefile b/usr.sbin/bad144/Makefile
new file mode 100644
index 0000000..1b87ea2
--- /dev/null
+++ b/usr.sbin/bad144/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= bad144
+MAN8= 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 0000000..e3843de
--- /dev/null
+++ b/usr.sbin/bad144/bad144.8
@@ -0,0 +1,186 @@
+.\" 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.
+.\"
+.\" @(#)bad144.8 8.1 (Berkeley) 6/6/93
+.\"
+.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 /kernel
+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 0000000..0afa9e4
--- /dev/null
+++ b/usr.sbin/bad144/bad144.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 1993, 198019861988
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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, 198019861988\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)bad144.c 8.1 (Berkeley) 6/6/93";
+#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 */
+#define RAWPART "c" /* disk partition containing badsector tables */
+
+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 0
+
+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, "%s/r%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);
+ 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;
+ if (dp->d_magic != DISKMAGIC || dp->d_magic2 != DISKMAGIC) {
+ 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);
+ }
+ 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
+ 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 0000000..e4ae04c
--- /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 0000000..0616548
--- /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 0000000..00683f0
--- /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 0000000..466cabc
--- /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 0000000..e661b6b
--- /dev/null
+++ b/usr.sbin/bootpd/Makefile
@@ -0,0 +1,15 @@
+# bootpd/Makefile
+# $Id: Makefile,v 1.1.1.1 1994/09/10 14:44:53 csgr Exp $
+
+PROG= bootpd
+#CFLAGS+= -DETC_ETHERS
+CFLAGS+= -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 rtmsg.c
+
+MAN5= bootptab.5
+MAN8= bootpd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/bootpd/Makefile.UNIX b/usr.sbin/bootpd/Makefile.UNIX
new file mode 100644
index 0000000..e333ce5
--- /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 0000000..9478676
--- /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 0000000..c7755b7
--- /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 0000000..990bf58
--- /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.2 1994/08/22 22:14:40 gwr 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 */
+ unsigned 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 */
+ unsigned 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 0000000..da59c21
--- /dev/null
+++ b/usr.sbin/bootpd/bootpd.8
@@ -0,0 +1,305 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /b/source/CVS/src/usr.sbin/bootpd/bootpd.8,v 1.2 1994/08/22 22:14:41 gwr 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 0000000..fc7a5dd
--- /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.4 1994/08/24 18:14:44 gwr 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 ((int) signal(SIGHUP, catcher) < 0) {
+ report(LOG_ERR, "signal: %s", get_errmsg());
+ exit(1);
+ }
+ if ((int) 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 0000000..e5ce341
--- /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;
+ unsigned 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 0000000..0f0b1fc
--- /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 0000000..4b2e3f4
--- /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.2 1994/08/22 22:14:46 gwr 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 0000000..f157cca
--- /dev/null
+++ b/usr.sbin/bootpd/bootpgw.c
@@ -0,0 +1,675 @@
+/*
+ * 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.2 1994/08/22 22:14:48 gwr 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 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 */
+};
+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;
+int32 server_ipa; /* Real server IP address, network order. */
+
+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 (isdigit(servername[0]))
+ server_ipa = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "bootpgw: can't get addr for %s\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, (char *)&server_ipa, sizeof(server_ipa));
+ }
+
+ 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(recv_addr);
+ n = recvfrom(s, pktbuf, MAX_MSG_SIZE, 0,
+ (struct sockaddr *) &recv_addr, &ra_len);
+ if (n <= 0) {
+ continue;
+ }
+ if (debug > 3) {
+ 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;
+
+ 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 = recv_addr here? */
+
+ if (debug) {
+ report(LOG_INFO, "request from %s",
+ inet_ntoa(recv_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, "reqest from %s reached hop limit",
+ inet_ntoa(recv_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, &recv_addr.sin_addr);
+ if (!ifr) {
+ report(LOG_NOTICE, "no interface for request from %s",
+ inet_ntoa(recv_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. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_port = htons(bootps_port);
+ send_addr.sin_addr.s_addr = server_ipa;
+
+ /* 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());
+ }
+}
+
+
+
+/*
+ * 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. */
+ send_addr.sin_family = AF_INET;
+ send_addr.sin_addr = bp->bp_yiaddr;
+ send_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 *) &send_addr,
+ sizeof(send_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 0000000..2cf1147
--- /dev/null
+++ b/usr.sbin/bootpd/bootptab.5
@@ -0,0 +1,395 @@
+.\" Copyright (c) 1988, 1989, 1991 Carnegie Mellon University
+.\"
+.\" $Header: /b/source/CVS/src/usr.sbin/bootpd/bootptab.5,v 1.2 1994/08/22 22:14:51 gwr 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 0000000..66212d4
--- /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 0000000..6fa04d1
--- /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 0000000..d076c8b
--- /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 0000000..bc235ac
--- /dev/null
+++ b/usr.sbin/bootpd/bootptest.c
@@ -0,0 +1,500 @@
+/*
+ * 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;
+ int32 server_addr; /* inet addr, network order */
+ 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 (isdigit(servername[0]))
+ server_addr = inet_addr(servername);
+ else {
+ hep = gethostbyname(servername);
+ if (!hep) {
+ fprintf(stderr, "%s: unknown host\n", servername);
+ exit(1);
+ }
+ bcopy(hep->h_addr, &server_addr, sizeof(server_addr));
+ }
+ } else {
+ /* Get broadcast address */
+ /* XXX - not yet */
+ server_addr = INADDR_ANY;
+ }
+ sin_server.sin_family = AF_INET;
+ sin_server.sin_port = htons(bootps_port);
+ sin_server.sin_addr.s_addr = server_addr;
+
+ /*
+ * 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 0000000..27f78ba
--- /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 0000000..537da4e
--- /dev/null
+++ b/usr.sbin/bootpd/bptypes.h
@@ -0,0 +1,23 @@
+/* bptypes.h */
+
+#ifndef BPTYPES_H
+#define BPTYPES_H
+
+/*
+ * 32 bit integers are different types on various architectures
+ */
+
+#ifndef int32
+#define int32 long
+#endif
+typedef unsigned int32 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 0000000..ba6ab28
--- /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 0000000..b30c982
--- /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 0000000..8c049b9
--- /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;
+ long 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 0000000..d131b50
--- /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 0000000..6cc1649
--- /dev/null
+++ b/usr.sbin/bootpd/getif.c
@@ -0,0 +1,145 @@
+/*
+ * getif.c : get an interface structure
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.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 0000000..c51dafd
--- /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 0000000..c1d33bb
--- /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.2 1994/08/22 22:14:58 gwr 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 0000000..51d0a5e
--- /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 0000000..840b953
--- /dev/null
+++ b/usr.sbin/bootpd/hwaddr.c
@@ -0,0 +1,294 @@
+/*
+ * 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
+
+/* For BSD 4.4, set arp entry by writing to routing socket */
+#if defined(BSD)
+#if BSD >= 199306
+extern int bsd_arp_set __P((struct in_addr *, char *, int));
+#endif
+#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 */
+#if defined(BSD) && (BSD >= 199306)
+ bsd_arp_set(ia, ha, len);
+#else /* Not BSD 4.4, and SIOCSARP not defined */
+ /*
+ * Oh well, SIOCSARP is not defined. Just run arp(8).
+ * XXX - Gag!
+ */
+ char buf[256];
+ int status;
+
+ sprintf(buf, "arp -s %s %s temp",
+ inet_ntoa(*ia), 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 /* ! 4.4 BSD */
+#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 0000000..dea7158
--- /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 0000000..2a30a59
--- /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 0000000..04805d8
--- /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 0000000..782959e
--- /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 0000000..1919e7f
--- /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.2 1994/08/22 22:15:01 gwr 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 0000000..1f70b45
--- /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.2 1994/08/22 22:15:04 gwr 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 0000000..3913455
--- /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 0000000..4f7f036
--- /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 0000000..0bf63d6
--- /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/rtmsg.c b/usr.sbin/bootpd/rtmsg.c
new file mode 100644
index 0000000..6de6102
--- /dev/null
+++ b/usr.sbin/bootpd/rtmsg.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 1984, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 1994
+ * Geoffrey M. Rehmet, All rights reserved.
+ *
+ * This code is derived from software which forms part of the 4.4-Lite
+ * Berkeley software distribution, which was in 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.
+ */
+
+/*
+ * from arp.c 8.2 (Berkeley) 1/2/94
+ * $Id$
+ */
+
+#include <sys/param.h>
+/*
+ * Verify that we are at least 4.4 BSD
+ */
+#if defined(BSD)
+#if BSD >= 199306
+
+#include <sys/socket.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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "report.h"
+
+
+static int rtmsg __P((int));
+
+static int s = -1; /* routing socket */
+
+
+/*
+ * Open the routing socket
+ */
+static void getsocket () {
+ if (s < 0) {
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ report(LOG_ERR, "socket %s", strerror(errno));
+ exit(1);
+ }
+ }
+}
+
+static struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
+static struct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
+static struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
+static int expire_time, flags, export_only, doing_proxy;
+static struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+/*
+ * Set an individual arp entry
+ */
+int bsd_arp_set(ia, eaddr, len)
+ struct in_addr *ia;
+ char *eaddr;
+ int len;
+{
+ register struct sockaddr_inarp *sin = &sin_m;
+ register struct sockaddr_dl *sdl;
+ register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
+ u_char *ea;
+ struct timeval time;
+
+ getsocket();
+ sdl_m = blank_sdl;
+ sin_m = blank_sin;
+ sin->sin_addr = *ia;
+
+ ea = (u_char *)LLADDR(&sdl_m);
+ bcopy(eaddr, ea, len);
+ sdl_m.sdl_alen = len;
+ doing_proxy = flags = export_only = expire_time = 0;
+
+ /* make arp entry temporary */
+ gettimeofday(&time, 0);
+ expire_time = time.tv_sec + 20 * 60;
+
+tryagain:
+ if (rtmsg(RTM_GET) < 0) {
+ report(LOG_WARNING, "rtmget: %s", strerror(errno));
+ 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) {
+ report(LOG_WARNING, "set: can only proxy for %s\n",
+ inet_ntoa(sin->sin_addr));
+ return (1);
+ }
+ if (sin_m.sin_other & SIN_PROXY) {
+ report(LOG_WARNING,
+ "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) {
+ report(LOG_WARNING,
+ "cannot intuit interface index and type for %s\n",
+ inet_ntoa(sin->sin_addr));
+ return (1);
+ }
+ sdl_m.sdl_type = sdl->sdl_type;
+ sdl_m.sdl_index = sdl->sdl_index;
+ return (rtmsg(RTM_ADD));
+}
+
+
+static int rtmsg(cmd)
+ int cmd;
+{
+ static int seq;
+ int rlen;
+ register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
+ register char *cp = m_rtmsg.m_space;
+ register int l;
+
+ errno = 0;
+ bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
+ rtm->rtm_flags = flags;
+ rtm->rtm_version = RTM_VERSION;
+
+ switch (cmd) {
+ default:
+ report(LOG_ERR, "set_arp: internal wrong cmd - exiting");
+ exit(1);
+ 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)) { \
+ bcopy((char *)&s, cp, 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;
+
+ l = rtm->rtm_msglen;
+ rtm->rtm_seq = ++seq;
+ rtm->rtm_type = cmd;
+ if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
+ if ((errno != ESRCH) && !(errno == EEXIST && cmd == RTM_ADD)){
+ report(LOG_WARNING, "writing to routing socket: %s",
+ strerror(errno));
+ return (-1);
+ }
+ }
+ do {
+ l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
+ } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != getpid()));
+ if (l < 0)
+ report(LOG_WARNING, "arp: read from routing socket: %s\n",
+ strerror(errno));
+ return (0);
+}
+
+#endif /* BSD */
+#endif /* BSD >= 199306 */
diff --git a/usr.sbin/bootpd/syslog.conf b/usr.sbin/bootpd/syslog.conf
new file mode 100644
index 0000000..2c135af
--- /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 0000000..e9314ae
--- /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 0000000..c6bb098
--- /dev/null
+++ b/usr.sbin/bootpd/trygetif.c
@@ -0,0 +1,68 @@
+/*
+ * 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 (isdigit(argv[1][0]))
+ dst_addr.s_addr = inet_addr(argv[1]);
+ else {
+ 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 0000000..40652a2
--- /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 0000000..4adc4ae
--- /dev/null
+++ b/usr.sbin/bootpd/tzone.c
@@ -0,0 +1,44 @@
+/*
+ * tzone.c - get the timezone
+ *
+ * This is shared by bootpd and bootpef
+ */
+
+#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 0000000..ddd67c4
--- /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 0000000..4abb5f1
--- /dev/null
+++ b/usr.sbin/bootpef/Makefile
@@ -0,0 +1,17 @@
+# bootpef/Makefile
+# $Id: Makefile,v 1.2 1994/09/10 15:00:04 csgr Exp $
+
+PROG= bootpef
+SRCDIR= ${.CURDIR}/../bootpd
+#CFLAGS+= -DETC_ETHERS
+CFLAGS+= -DDEBUG -I${SRCDIR}
+.PATH: ${SRCDIR}
+MANSRC= ${SRCDIR}
+
+SRCS= bootpef.c dovend.c readfile.c hash.c dumptab.c \
+ lookup.c hwaddr.c report.c rtmsg.c tzone.c
+
+MAN8= bootpef.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/bootpgw/Makefile b/usr.sbin/bootpgw/Makefile
new file mode 100644
index 0000000..6be63f6
--- /dev/null
+++ b/usr.sbin/bootpgw/Makefile
@@ -0,0 +1,14 @@
+# bootpgw/Makefile
+# $Id: Makefile,v 1.1.1.1 1994/09/10 14:44:56 csgr Exp $
+
+PROG= bootpgw
+SRCDIR= ${.CURDIR}/../bootpd
+CFLAGS+= -DSYSLOG -DDEBUG -I${SRCDIR}
+.PATH: ${SRCDIR}
+
+SRCS= bootpgw.c getif.c hwaddr.c report.c rtmsg.c
+
+MAN8=
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/bootptest/Makefile b/usr.sbin/bootptest/Makefile
new file mode 100644
index 0000000..35e9867
--- /dev/null
+++ b/usr.sbin/bootptest/Makefile
@@ -0,0 +1,15 @@
+# bootptest/Makefile
+# $Id: Makefile,v 1.3 1994/08/22 22:19:04 gwr Exp $
+
+PROG= bootptest
+SRCDIR= ${.CURDIR}/../bootpd
+CFLAGS+= -I${SRCDIR}
+.PATH: ${SRCDIR}
+MANSRC= ${SRCDIR}
+
+SRCS= bootptest.c print-bootp.c getif.c getether.c report.c
+
+MAN8= bootptest.8
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/chown/Makefile b/usr.sbin/chown/Makefile
new file mode 100644
index 0000000..9a4974c
--- /dev/null
+++ b/usr.sbin/chown/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= chown
+CFLAGS+=-DSUPPORT_DOT
+MAN1= chgrp.1
+MAN8= 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 0000000..1adcb80
--- /dev/null
+++ b/usr.sbin/chown/chgrp.1
@@ -0,0 +1,136 @@
+.\" 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.
+.\"
+.\" @(#)chgrp.1 8.3 (Berkeley) 3/31/94
+.\"
+.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 0000000..f0cd533
--- /dev/null
+++ b/usr.sbin/chown/chown.8
@@ -0,0 +1,149 @@
+.\" 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.
+.\"
+.\" @(#)chown.8 8.3 (Berkeley) 3/31/94
+.\"
+.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 0000000..5dd0867
--- /dev/null
+++ b/usr.sbin/chown/chown.c
@@ -0,0 +1,273 @@
+/*
+ * 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
+static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94";
+#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. */
+ continue;
+ fts_set(ftsp, p, FTS_SKIP);
+ break;
+ 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) {
+ chownerr(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
+chownerr(file)
+ char *file;
+{
+ static int euid = -1, ngroups = -1;
+ gid_t groups[NGROUPS];
+
+ /* Check for chown without being root. */
+ if (errno != EPERM ||
+ uid != -1 && euid == -1 && (euid = geteuid()) != 0) {
+ if (fflag)
+ exit(0);
+ err(1, "%s", file);
+ }
+
+ /* Check group membership; kernel just returns EPERM. */
+ if (gid != -1 && ngroups == -1) {
+ ngroups = getgroups(NGROUPS, groups);
+ while (--ngroups >= 0 && gid != groups[ngroups]);
+ if (ngroups < 0) {
+ if (fflag)
+ exit(0);
+ errx(1, "you are not a member of group %s", gname);
+ }
+ }
+
+ if (!fflag)
+ warn("%s", file);
+}
+
+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 0000000..69fe8b8
--- /dev/null
+++ b/usr.sbin/chroot/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= chroot
+MAN8= 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 0000000..76f488b
--- /dev/null
+++ b/usr.sbin/chroot/chroot.8
@@ -0,0 +1,79 @@
+.\" 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.
+.\"
+.\" @(#)chroot.8 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.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 chroot
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c
new file mode 100644
index 0000000..81bf675
--- /dev/null
+++ b/usr.sbin/chroot/chroot.c
@@ -0,0 +1,96 @@
+/*
+ * 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[] = "@(#)chroot.c 8.1 (Berkeley) 6/9/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.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[];
+{
+ int ch;
+ char *shell;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ if (chdir(argv[0]) || chroot("."))
+ err(1, "%s", argv[0]);
+
+ if (argv[1]) {
+ execvp(argv[1], &argv[1]);
+ err(1, "%s", argv[1]);
+ }
+
+ if (!(shell = getenv("SHELL")))
+ shell = _PATH_BSHELL;
+ execlp(shell, shell, "-i", NULL);
+ err(1, "%s", shell);
+ /* NOTREACHED */
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: chroot newroot [command]\n");
+ exit(1);
+}
diff --git a/usr.sbin/config.new/Makefile b/usr.sbin/config.new/Makefile
new file mode 100644
index 0000000..f6931e1
--- /dev/null
+++ b/usr.sbin/config.new/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 8.2 (Berkeley) 4/19/94
+
+PROG= config.new
+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.
+CLEANFILES=gram.c scan.c y.tab.h
+MAN8= config.new.8
+
+.include <bsd.prog.mk>
+
+.depend: gram.c scan.c
diff --git a/usr.sbin/config.new/config.h b/usr.sbin/config.new/config.h
new file mode 100644
index 0000000..a36abbd
--- /dev/null
+++ b/usr.sbin/config.new/config.h
@@ -0,0 +1,281 @@
+/*
+ * 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.
+ *
+ * @(#)config.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * 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; /* "kernel" */
+ 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" */
+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 */
+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.new/config.new.8 b/usr.sbin/config.new/config.new.8
new file mode 100644
index 0000000..5eae8d3
--- /dev/null
+++ b/usr.sbin/config.new/config.new.8
@@ -0,0 +1,167 @@
+.\" 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.
+.\"
+.\" @(#)config.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt CONFIG.NEW 8
+.Os BSD 4
+.Sh NAME
+.Nm config.new
+.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/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
+command appeared in
+.Bx 4.1 .
+It was completely revised in
+.Bx 4.4 .
diff --git a/usr.sbin/config.new/files.c b/usr.sbin/config.new/files.c
new file mode 100644
index 0000000..40cddf8
--- /dev/null
+++ b/usr.sbin/config.new/files.c
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ *
+ * @(#)files.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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.new/gram.y b/usr.sbin/config.new/gram.y
new file mode 100644
index 0000000..6b53801
--- /dev/null
+++ b/usr.sbin/config.new/gram.y
@@ -0,0 +1,392 @@
+%{
+
+/*
+ * 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.
+ *
+ * @(#)gram.y 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.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 *));
+
+%}
+
+%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 MINOR
+%token 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 */
+ specs; /* rest of machine description */
+
+hdrs:
+ hdrs hdr |
+ /* empty */;
+
+hdr:
+ include |
+ '\n';
+
+machine_spec:
+ XMACHINE WORD = { setmachine($2); } |
+ error = { stop("cannot proceed without machine specifier"); };
+
+dev_eof:
+ ENDFILE = { enddefs(lastfile); checkfiles(); };
+
+
+
+/*
+ * 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)
+ const char *mch;
+{
+ char buf[MAXPATHLEN];
+
+ machine = mch;
+ (void)sprintf(buf, "files.%s", mch);
+ if (include(buf, ENDFILE) ||
+ include("../../conf/files.newconf", ENDFILE))
+ exit(1);
+}
diff --git a/usr.sbin/config.new/hash.c b/usr.sbin/config.new/hash.c
new file mode 100644
index 0000000..d7617da
--- /dev/null
+++ b/usr.sbin/config.new/hash.c
@@ -0,0 +1,279 @@
+/*
+ * 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.
+ *
+ * @(#)hash.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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.new/main.c b/usr.sbin/config.new/main.c
new file mode 100644
index 0000000..50b930e
--- /dev/null
+++ b/usr.sbin/config.new/main.c
@@ -0,0 +1,466 @@
+/*
+ * 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.
+ *
+ * @(#)main.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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.
+ */
+static int
+mksymlinks()
+{
+ int ret;
+ char *p, buf[200];
+
+ p = path("machine");
+ (void)sprintf(buf, "../../%s/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);
+ 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;
+ 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) >> 3))
+ continue;
+ (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++;
+ }
+ 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.new/mkheaders.c b/usr.sbin/config.new/mkheaders.c
new file mode 100644
index 0000000..f627243
--- /dev/null
+++ b/usr.sbin/config.new/mkheaders.c
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ *
+ * @(#)mkheaders.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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.new/mkioconf.c b/usr.sbin/config.new/mkioconf.c
new file mode 100644
index 0000000..8b1ebe0
--- /dev/null
+++ b/usr.sbin/config.new/mkioconf.c
@@ -0,0 +1,395 @@
+/*
+ * 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.
+ *
+ * @(#)mkioconf.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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.new/mkmakefile.c b/usr.sbin/config.new/mkmakefile.c
new file mode 100644
index 0000000..06971a5
--- /dev/null
+++ b/usr.sbin/config.new/mkmakefile.c
@@ -0,0 +1,364 @@
+/*
+ * 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.
+ *
+ * @(#)mkmakefile.c 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/param.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.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%s%s", sp, nv->nv_name,
+ nv->nv_str ? "=" : "", nv->nv_str ? 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/%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/%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.new/mkswap.c b/usr.sbin/config.new/mkswap.c
new file mode 100644
index 0000000..afea210
--- /dev/null
+++ b/usr.sbin/config.new/mkswap.c
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ *
+ * @(#)mkswap.c 8.1 (Berkeley) 6/6/93
+ */
+
+#include <sys/param.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.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 int
+mkoneswap(cf)
+ register struct config *cf;
+{
+ register struct nvlist *nv;
+ register FILE *fp;
+ register char *fname;
+ char buf[200];
+
+ (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 = makedev(%d, %d);\t/* %s */\n",
+ major(nv->nv_int), minor(nv->nv_int), nv->nv_str) < 0)
+ goto wrerror;
+ nv = cf->cf_dump;
+ if (fprintf(fp, "dev_t\tdumpdev = makedev(%d, %d);\t/* %s */\n",
+ major(nv->nv_int), minor(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{ makedev(%d, %d),\t0,\t0 },\t/* %s */\n",
+ major(nv->nv_int), minor(nv->nv_int), nv->nv_str) < 0)
+ goto wrerror;
+ if (fputs("\t{ NODEV, 0, 0 }\n};\n", fp) < 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.new/pack.c b/usr.sbin/config.new/pack.c
new file mode 100644
index 0000000..8b525ec
--- /dev/null
+++ b/usr.sbin/config.new/pack.c
@@ -0,0 +1,520 @@
+/*
+ * 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.
+ *
+ * @(#)pack.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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) (((int)(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.new/scan.l b/usr.sbin/config.new/scan.l
new file mode 100644
index 0000000..b7301a3
--- /dev/null
+++ b/usr.sbin/config.new/scan.l
@@ -0,0 +1,238 @@
+%{
+/*
+ * 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.
+ *
+ * @(#)scan.l 8.1 (Berkeley) 6/6/93
+ */
+
+#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; }
+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 = strtol(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.new/sem.c b/usr.sbin/config.new/sem.c
new file mode 100644
index 0000000..aa60169
--- /dev/null
+++ b/usr.sbin/config.new/sem.c
@@ -0,0 +1,974 @@
+/*
+ * 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.
+ *
+ * @(#)sem.c 8.1 (Berkeley) 6/6/93
+ */
+
+#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 */
+
+static const char *s_generic;
+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_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*8 + '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') >= 7)
+ panic("resolve");
+ if ((nv = *nvp) == NULL) {
+ /*
+ * Apply default. Easiest to do this by number.
+ */
+ maj = major(dflt->nv_int);
+ min = (minor(dflt->nv_int) & ~7) | part;
+ *nvp = nv = newnv(NULL, NULL, NULL, makedev(maj, min));
+ }
+ 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 >> 3, (min & 7) + 'a');
+ nv->nv_str = intern(buf);
+ 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 <= 'h' && 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 * 8 + 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.new/sem.h b/usr.sbin/config.new/sem.h
new file mode 100644
index 0000000..14d6c2b
--- /dev/null
+++ b/usr.sbin/config.new/sem.h
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ *
+ * @(#)sem.h 8.1 (Berkeley) 6/6/93
+ */
+
+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));
diff --git a/usr.sbin/config.new/util.c b/usr.sbin/config.new/util.c
new file mode 100644
index 0000000..6ef37db
--- /dev/null
+++ b/usr.sbin/config.new/util.c
@@ -0,0 +1,262 @@
+/*
+ * 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.
+ *
+ * @(#)util.c 8.1 (Berkeley) 6/6/93
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+#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/config/Makefile b/usr.sbin/config/Makefile
new file mode 100644
index 0000000..d59ea40
--- /dev/null
+++ b/usr.sbin/config/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= config
+CFLAGS+=-I. -I${.CURDIR} -DSTATCLOCK
+.if defined(CONFIG_DONT_CLOBBER)
+CFLAGS+= -DCONFIG_DONT_CLOBBER
+.endif
+SRCS= config.c main.c lang.c mkioconf.c mkmakefile.c mkglue.c mkheaders.c \
+ mkswapconf.c
+MAN8= config.8
+DPADD= ${LIBL}
+LDADD= -ll
+CLEANFILES+=y.tab.h lang.c config.c y.tab.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/config/SMM.doc/0.t b/usr.sbin/config/SMM.doc/0.t
new file mode 100644
index 0000000..ae5bf77
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/0.t
@@ -0,0 +1,88 @@
+.\" 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) 7/5/93
+.\"
+.bd S B 3
+.de UX
+.ie \\n(GA>0 \\$2UNIX\\$1
+.el \{\
+.if n \\$2UNIX\\$1*
+.if t \\$2UNIX\\$1\\f1\(dg\\fP
+.FS
+.if n *UNIX
+.if t \(dgUNIX
+.ie \\$3=1 is a Footnote of Bell Laboratories.
+.el is a Trademark of Bell Laboratories.
+.FE
+.nr GA 1\}
+..
+.de BR
+\fB\\$1\fP\\$2
+..
+.TL
+Building 4.4BSD Kernels with Config
+.AU
+Samuel J. Leffler and Michael J. Karels
+.AI
+Computer Systems Research Group
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, California 94720
+.de IR
+\fI\\$1\fP\\$2
+..
+.de DT
+.TA 8 16 24 32 40 48 56 64 72 80
+..
+.AB
+.PP
+This document describes the use of
+\fIconfig\fP\|(8) to configure and create bootable
+4.4BSD system images.
+It discusses the structure of system
+configuration files and how to configure
+systems with non-standard hardware configurations.
+Sections describing the preferred way to
+add new code to the system and how the system's autoconfiguration
+process operates are included. An appendix
+contains a summary of the rules used by the system
+in calculating the size of system data structures,
+and also indicates some of the standard system size
+limitations (and how to change them).
+Other configuration options are also listed.
+.sp
+.LP
+Revised July 5, 1993
+.AE
+.LP
+.OH 'Building 4.4BSD Kernels with Config''SMM:2-%'
+.EH 'SMM:2-%''Building 4.4BSD Kernels with Config'
diff --git a/usr.sbin/config/SMM.doc/1.t b/usr.sbin/config/SMM.doc/1.t
new file mode 100644
index 0000000..453041b
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/1.t
@@ -0,0 +1,61 @@
+.\" 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
+.\"
+.\".ds RH Introduction
+.ne 2i
+.sp 3
+.NH
+INTRODUCTION
+.PP
+.I Config
+is a tool used in building 4.4BSD system images (the UNIX kernel).
+It takes a file describing a system's tunable parameters and
+hardware support, and generates a collection
+of files which are then used to build a copy of UNIX appropriate
+to that configuration.
+.I Config
+simplifies system maintenance by isolating system dependencies
+in a single, easy to understand, file.
+.PP
+This document describes the content and
+format of system configuration
+files and the rules which must be followed when creating
+these files. Example configuration files are constructed
+and discussed.
+.PP
+Later sections suggest guidelines to be used in modifying
+system source and explain some of the inner workings of the
+autoconfiguration process. Appendix D summarizes the rules
+used in calculating the most important system data structures
+and indicates some inherent system data structure size
+limitations (and how to go about modifying them).
diff --git a/usr.sbin/config/SMM.doc/2.t b/usr.sbin/config/SMM.doc/2.t
new file mode 100644
index 0000000..34e6b63
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/2.t
@@ -0,0 +1,188 @@
+.\" 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
+.\"
+.\".ds RH "Configuration File Contents
+.ne 2i
+.NH
+CONFIGURATION FILE CONTENTS
+.PP
+A system configuration must include at least the following
+pieces of information:
+.IP \(bu 3
+machine type
+.IP \(bu 3
+cpu type
+.IP \(bu 3
+system identification
+.IP \(bu 3
+timezone
+.IP \(bu 3
+maximum number of users
+.IP \(bu 3
+location of the root file system
+.IP \(bu 3
+available hardware
+.PP
+.I Config
+allows multiple system images to be generated from a single
+configuration description. Each system image is configured
+for identical hardware, but may have different locations for the root
+file system and, possibly, other system devices.
+.NH 2
+Machine type
+.PP
+The
+.I "machine type"
+indicates if the system is going to operate on a DEC VAX-11\(dg computer,
+.FS
+\(dg DEC, VAX, UNIBUS, MASSBUS and MicroVAX are trademarks of Digital
+Equipment Corporation.
+.FE
+or some other machine on which 4.4BSD operates. The machine type
+is used to locate certain data files which are machine specific, and
+also to select rules used in constructing the resultant
+configuration files.
+.NH 2
+Cpu type
+.PP
+The
+.I "cpu type"
+indicates which, of possibly many, cpu's the system is to operate on.
+For example, if the system is being configured for a VAX-11, it could
+be running on a VAX 8600, VAX-11/780, VAX-11/750, VAX-11/730 or MicroVAX II.
+(Other VAX cpu types, including the 8650, 785 and 725, are configured using
+the cpu designation for compatible machines introduced earlier.)
+Specifying
+more than one cpu type implies that the system should be configured to run
+on any of the cpu's specified. For some types of machines this is not
+possible and
+.I config
+will print a diagnostic indicating such.
+.NH 2
+System identification
+.PP
+The
+.I "system identification"
+is a moniker attached to the system, and often the machine on which the
+system is to run. For example, at Berkeley we have machines named Ernie
+(Co-VAX), Kim (No-VAX), and so on. The system identifier selected is used to
+create a global C ``#define'' which may be used to isolate system dependent
+pieces of code in the kernel. For example, Ernie's Varian driver used
+to be special cased because its interrupt vectors were wired together. The
+code in the driver which understood how to handle this non-standard hardware
+configuration was conditionally compiled in only if the system
+was for Ernie.
+.PP
+The system identifier ``GENERIC'' is given to a system which
+will run on any cpu of a particular machine type; it should not
+otherwise be used for a system identifier.
+.NH 2
+Timezone
+.PP
+The timezone in which the system is to run is used to define the
+information returned by the \fIgettimeofday\fP\|(2)
+system call. This value is specified as the number of hours east
+or west of GMT. Negative numbers indicate a value east of GMT.
+The timezone specification may also indicate the
+type of daylight savings time rules to be applied.
+.NH 2
+Maximum number of users
+.PP
+The system allocates many system data structures at boot time
+based on the maximum number of users the system will support.
+This number is normally between 8 and 40, depending
+on the hardware and expected job mix. The rules
+used to calculate system data structures are discussed in
+Appendix D.
+.NH 2
+Root file system location
+.PP
+When the system boots it must know the location of
+the root of the file system
+tree. This location and the part(s) of the disk(s) to be used
+for paging and swapping must be specified in order to create
+a complete configuration description.
+.I Config
+uses many rules to calculate default locations for these items;
+these are described in Appendix B.
+.PP
+When a generic system is configured, the root file system is left
+undefined until the system is booted. In this case, the root file
+system need not be specified, only that the system is a generic system.
+.NH 2
+Hardware devices
+.PP
+When the system boots it goes through an
+.I autoconfiguration
+phase. During this period, the system searches for all
+those hardware devices
+which the system builder has indicated might be present. This probing
+sequence requires certain pieces of information such as register
+addresses, bus interconnects, etc. A system's hardware may be configured
+in a very flexible manner or be specified without any flexibility
+whatsoever. Most people do not configure hardware devices into the
+system unless they are currently present on the machine, expect
+them to be present in the near future, or are simply guarding
+against a hardware
+failure somewhere else at the site (it is often wise to configure in
+extra disks in case an emergency requires moving one off a machine which
+has hardware problems).
+.PP
+The specification of hardware devices usually occupies the majority of
+the configuration file. As such, a large portion of this document will
+be spent understanding it. Section 6.3 contains a description of
+the autoconfiguration process, as it applies to those planning to
+write, or modify existing, device drivers.
+.NH 2
+Pseudo devices
+.PP
+Several system facilities are configured in a manner like that used
+for hardware devices although they are not associated with specific hardware.
+These system options are configured as
+.IR pseudo-devices .
+Some pseudo devices allow an optional parameter that sets the limit
+on the number of instances of the device that are active simultaneously.
+.NH 2
+System options
+.PP
+Other than the mandatory pieces of information described above, it
+is also possible to include various optional system facilities
+or to modify system behavior and/or limits.
+For example, 4.4BSD can be configured to support binary compatibility for
+programs built under 4.3BSD. Also, optional support is provided
+for disk quotas and tracing the performance of the virtual memory
+subsystem. Any optional facilities to be configured into
+the system are specified in the configuration file. The resultant
+files generated by
+.I config
+will automatically include the necessary pieces of the system.
diff --git a/usr.sbin/config/SMM.doc/3.t b/usr.sbin/config/SMM.doc/3.t
new file mode 100644
index 0000000..e0b6234
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/3.t
@@ -0,0 +1,299 @@
+.\" 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
+.\"
+.\".ds RH "System Building Process
+.ne 2i
+.NH
+SYSTEM BUILDING PROCESS
+.PP
+In this section we consider the steps necessary to build a bootable system
+image. We assume the system source is located in the ``/sys'' directory
+and that, initially, the system is being configured from source code.
+.PP
+Under normal circumstances there are 5 steps in building a system.
+.IP 1) 3
+Create a configuration file for the system.
+.IP 2) 3
+Make a directory for the system to be constructed in.
+.IP 3) 3
+Run
+.I config
+on the configuration file to generate the files required
+to compile and load the system image.
+.IP 4)
+Construct the source code interdependency rules for the
+configured system with
+.I make depend
+using
+.IR make (1).
+.IP 5)
+Compile and load the system with
+.IR make .
+.PP
+Steps 1 and 2 are usually done only once. When a system configuration
+changes it usually suffices to just run
+.I config
+on the modified configuration file, rebuild the source code dependencies,
+and remake the system. Sometimes,
+however, configuration dependencies may not be noticed in which case
+it is necessary to clean out the relocatable object files saved
+in the system's directory; this will be discussed later.
+.NH 2
+Creating a configuration file
+.PP
+Configuration files normally reside in the directory ``/sys/conf''.
+A configuration file is most easily constructed by copying an
+existing configuration file and modifying it. The 4.4BSD distribution
+contains a number of configuration files for machines at Berkeley;
+one may be suitable or, in worst case, a copy
+of the generic configuration file may be edited.
+.PP
+The configuration file must have the same name as the directory in
+which the configured system is to be built.
+Further,
+.I config
+assumes this directory is located in the parent directory of
+the directory in which it
+is run. For example, the generic
+system has a configuration file ``/sys/conf/GENERIC'' and an accompanying
+directory named ``/sys/GENERIC''.
+Although it is not required that the system sources and configuration
+files reside in ``/sys,'' the configuration and compilation procedure
+depends on the relative locations of directories within that hierarchy,
+as most of the system code and the files created by
+.I config
+use pathnames of the form ``../''.
+If the system files are not located in ``/sys,''
+it is desirable to make a symbolic link there for use in installation
+of other parts of the system that share files with the kernel.
+.PP
+When building the configuration file, be sure to include the items
+described in section 2. In particular, the machine type,
+cpu type, timezone, system identifier, maximum users, and root device
+must be specified. The specification of the hardware present may take
+a bit of work; particularly if your hardware is configured at non-standard
+places (e.g. device registers located at funny places or devices not
+supported by the system). Section 4 of this document
+gives a detailed description of the configuration file syntax,
+section 5 explains some sample configuration files, and
+section 6 discusses how to add new devices to
+the system. If the devices to be configured are not already
+described in one of the existing configuration files you should check
+the manual pages in section 4 of the UNIX Programmers Manual. For each
+supported device, the manual page synopsis entry gives a
+sample configuration line.
+.PP
+Once the configuration file is complete, run it through
+.I config
+and look for any errors. Never try and use a system which
+.I config
+has complained about; the results are unpredictable.
+For the most part,
+.IR config 's
+error diagnostics are self explanatory. It may be the case that
+the line numbers given with the error messages are off by one.
+.PP
+A successful run of
+.I config
+on your configuration file will generate a number of files in
+the configuration directory. These files are:
+.IP \(bu 3
+A file to be used by \fImake\fP\|(1)
+in compiling and loading the system,
+.IR Makefile .
+.IP \(bu 3
+One file for each possible system image for this machine,
+.IR swapxxx.c ,
+where
+.I xxx
+is the name of the system image,
+which describes where swapping, the root file system, and other
+miscellaneous system devices are located.
+.IP \(bu 3
+A collection of header files, one per possible device the
+system supports, which define the hardware configured.
+.IP \(bu 3
+A file containing the I/O configuration tables used by the system
+during its
+.I autoconfiguration
+phase,
+.IR ioconf.c .
+.IP \(bu 3
+An assembly language file of interrupt vectors which
+connect interrupts from the machine's external buses to the main
+system path for handling interrupts,
+and a file that contains counters and names for the interrupt vectors.
+.PP
+Unless you have reason to doubt
+.IR config ,
+or are curious how the system's autoconfiguration scheme
+works, you should never have to look at any of these files.
+.NH 2
+Constructing source code dependencies
+.PP
+When
+.I config
+is done generating the files needed to compile and link your system it
+will terminate with a message of the form ``Don't forget to run make depend''.
+This is a reminder that you should change over to the configuration
+directory for the system just configured and type ``make depend''
+to build the rules used by
+.I make
+to recognize interdependencies in the system source code.
+This will insure that any changes to a piece of the system
+source code will result in the proper modules being recompiled
+the next time
+.I make
+is run.
+.PP
+This step is particularly important if your site makes changes
+to the system include files. The rules generated specify which source code
+files are dependent on which include files. Without these rules,
+.I make
+will not recognize when it must rebuild modules
+due to the modification of a system header file.
+The dependency rules are generated by a pass of the C preprocessor
+and reflect the global system options.
+This step must be repeated when the configuration file is changed
+and
+.I config
+is used to regenerate the system makefile.
+.NH 2
+Building the system
+.PP
+The makefile constructed by
+.I config
+should allow a new system to be rebuilt by simply typing ``make image-name''.
+For example, if you have named your bootable system image ``kernel'',
+then ``make kernel''
+will generate a bootable image named ``kernel''. Alternate system image names
+are used when the root file system location and/or swapping configuration
+is done in more than one way. The makefile which
+.I config
+creates has entry points for each system image defined in
+the configuration file.
+Thus, if you have configured ``kernel'' to be a system with the root file
+system on an ``hp'' device and ``hkkernel'' to be a system with the root
+file system on an ``hk'' device, then ``make kernel hkkernel'' will generate
+binary images for each.
+As the system will generally use the disk from which it is loaded
+as the root filesystem, separate system images are only required
+to support different swap configurations.
+.PP
+Note that the name of a bootable image is different from the system
+identifier. All bootable images are configured for the same system;
+only the information about the root file system and paging devices differ.
+(This is described in more detail in section 4.)
+.PP
+The last step in the system building process is to rearrange certain commonly
+used symbols in the symbol table of the system image; the makefile
+generated by
+.I config
+does this automatically for you.
+This is advantageous for programs such as
+\fInetstat\fP\|(1) and \fIvmstat\fP\|(1),
+which run much faster when the symbols they need are located at
+the front of the symbol table.
+Remember also that many programs expect
+the currently executing system to be named ``/kernel''. If you install
+a new system and name it something other than ``/kernel'', many programs
+are likely to give strange results.
+.NH 2
+Sharing object modules
+.PP
+If you have many systems which are all built on a single machine
+there are at least two approaches to saving time in building system
+images. The best way is to have a single system image which is run on
+all machines. This is attractive since it minimizes disk space used
+and time required to rebuild systems after making changes. However,
+it is often the case that one or more systems will require a separately
+configured system image. This may be due to limited memory (building
+a system with many unused device drivers can be expensive), or to
+configuration requirements (one machine may be a development machine
+where disk quotas are not needed, while another is a production machine
+where they are), etc. In these cases it is possible
+for common systems to share relocatable object modules which are not
+configuration dependent; most of the modules in the directory ``/sys/sys''
+are of this sort.
+.PP
+To share object modules, a generic system should be built. Then, for
+each system configure the system as before, but before recompiling and
+linking the system, type ``make links'' in the system compilation directory.
+This will cause the system
+to be searched for source modules which are safe to share between systems
+and generate symbolic links in the current directory to the appropriate
+object modules in the directory ``../GENERIC''. A shell script,
+``makelinks'' is generated with this request and may be checked for
+correctness. The file ``/sys/conf/defines'' contains a list of symbols
+which we believe are safe to ignore when checking the source code
+for modules which may be shared. Note that this list includes the definitions
+used to conditionally compile in the virtual memory tracing facilities, and
+the trace point support used only rarely (even at Berkeley).
+It may be necessary
+to modify this file to reflect local needs. Note further that
+interdependencies which are not directly visible
+in the source code are not caught. This means that if you place
+per-system dependencies in an include file, they will not be recognized
+and the shared code may be selected in an unexpected fashion.
+.NH 2
+Building profiled systems
+.PP
+It is simple to configure a system which will automatically
+collect profiling information as it operates. The profiling data
+may be collected with \fIkgmon\fP\|(8) and processed with
+\fIgprof\fP\|(1)
+to obtain information regarding the system's operation. Profiled
+systems maintain histograms of the program counter as well as the
+number of invocations of each routine. The \fIgprof\fP
+command will also generate a dynamic call graph of the executing
+system and propagate time spent in each routine along the arcs
+of the call graph (consult the \fIgprof\fP documentation for elaboration).
+The program counter sampling can be driven by the system clock, or
+if you have an alternate real time clock, this can be used. The
+latter is highly recommended, as use of the system clock will result
+in statistical anomalies, and time spent in the clock routine will
+not be accurately attributed.
+.PP
+To configure a profiled system, the
+.B \-p
+option should be supplied to \fIconfig\fP.
+A profiled system is about 5-10% larger in its text space due to
+the calls to count the subroutine invocations. When the system
+executes, the profiling data is stored in a buffer which is 1.2
+times the size of the text space. The overhead for running a
+profiled system varies; under normal load we see anywhere from 5-25%
+of the system time spent in the profiling code.
+.PP
+Note that systems configured for profiling should not be shared as
+described above unless all the other shared systems are also to be
+profiled.
diff --git a/usr.sbin/config/SMM.doc/4.t b/usr.sbin/config/SMM.doc/4.t
new file mode 100644
index 0000000..7498185
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/4.t
@@ -0,0 +1,442 @@
+.\" 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
+.\"
+.\".ds RH "Configuration File Syntax
+.ne 2i
+.NH
+CONFIGURATION FILE SYNTAX
+.PP
+In this section we consider the specific rules used in writing
+a configuration file. A complete grammar for the input language
+can be found in Appendix A and may be of use if you should have
+problems with syntax errors.
+.PP
+A configuration file is broken up into three logical pieces:
+.IP \(bu 3
+configuration parameters global to all system images
+specified in the configuration file,
+.IP \(bu 3
+parameters specific to each
+system image to be generated, and
+.IP \(bu 3
+device specifications.
+.NH 2
+Global configuration parameters
+.PP
+The global configuration parameters are the type of machine,
+cpu types, options, timezone, system identifier, and maximum users.
+Each is specified with a separate line in the configuration file.
+.IP "\fBmachine\fP \fItype\fP"
+.br
+The system is to run on the machine type specified. No more than
+one machine type can appear in the configuration file. Legal values
+are
+.B vax
+and
+\fBsun\fP.
+.IP "\fBcpu\fP ``\fItype\fP''"
+.br
+This system is to run on the cpu type specified.
+More than one cpu type specification
+can appear in a configuration file.
+Legal types for a
+.B vax
+machine are
+\fBVAX8600\fP, \fBVAX780\fP, \fBVAX750\fP,
+\fBVAX730\fP
+and
+\fBVAX630\fP (MicroVAX II).
+The 8650 is listed as an 8600, the 785 as a 780, and a 725 as a 730.
+.IP "\fBoptions\fP \fIoptionlist\fP"
+.br
+Compile the listed optional code into the system.
+Options in this list are separated by commas.
+Possible options are listed at the top of the generic makefile.
+A line of the form ``options FUNNY,HAHA'' generates global ``#define''s
+\-DFUNNY \-DHAHA in the resultant makefile.
+An option may be given a value by following its name with ``\fB=\fP'',
+then the value enclosed in (double) quotes.
+The following are major options are currently in use:
+COMPAT (include code for compatibility with 4.1BSD binaries),
+INET (Internet communication protocols),
+NS (Xerox NS communication protocols),
+and
+QUOTA (enable disk quotas).
+Other kernel options controlling system sizes and limits
+are listed in Appendix D;
+options for the network are found in Appendix E.
+There are additional options which are associated with certain
+peripheral devices; those are listed in the Synopsis section
+of the manual page for the device.
+.IP "\fBmakeoptions\fP \fIoptionlist\fP"
+.br
+Options that are used within the system makefile
+and evaluated by
+.I make
+are listed as
+.IR makeoptions .
+Options are listed with their values with the form
+``makeoptions name=value,name2=value2.''
+The values must be enclosed in double quotes if they include numerals
+or begin with a dash.
+.IP "\fBtimezone\fP \fInumber\fP [ \fBdst\fP [ \fInumber\fP ] ]"
+.br
+Specifies the timezone used by the system. This is measured in the
+number of hours your timezone is west of GMT.
+EST is 5 hours west of GMT, PST is 8. Negative numbers
+indicate hours east of GMT. If you specify
+\fBdst\fP, the system will operate under daylight savings time.
+An optional integer or floating point number may be included
+to specify a particular daylight saving time correction algorithm;
+the default value is 1, indicating the United States.
+Other values are: 2 (Australian style), 3 (Western European),
+4 (Middle European), and 5 (Eastern European). See
+\fIgettimeofday\fP\|(2) and \fIctime\fP\|(3) for more information.
+.IP "\fBident\fP \fIname\fP"
+.br
+This system is to be known as
+.IR name .
+This is usually a cute name like ERNIE (short for Ernie Co-Vax) or
+VAXWELL (for Vaxwell Smart).
+This value is defined for use in conditional compilation,
+and is also used to locate an optional list of source files specific
+to this system.
+.IP "\fBmaxusers\fP \fInumber\fP"
+.br
+The maximum expected number of simultaneously active user on this system is
+.IR number .
+This number is used to size several system data structures.
+.NH 2
+System image parameters
+.PP
+Multiple bootable images may be specified in a single configuration
+file. The systems will have the same global configuration parameters
+and devices, but the location of the root file system and other
+system specific devices may be different. A system image is specified
+with a ``config'' line:
+.IP
+\fBconfig\fP\ \fIsysname\fP\ \fIconfig-clauses\fP
+.LP
+The
+.I sysname
+field is the name given to the loaded system image; almost everyone
+names their standard system image ``kernel''. The configuration clauses
+are one or more specifications indicating where the root file system
+is located and the number and location of paging devices.
+The device used by the system to process argument lists during
+.IR execve (2)
+calls may also be specified, though in practice this is almost
+always selected by
+.I config
+using one of its rules for selecting default locations for
+system devices.
+.PP
+A configuration clause is one of the following
+.IP
+.nf
+\fBroot\fP [ \fBon\fP ] \fIroot-device\fP
+\fBswap\fP [ \fBon\fP ] \fIswap-device\fP [ \fBand\fP \fIswap-device\fP ] ...
+\fBdumps\fP [ \fBon\fP ] \fIdump-device\fP
+\fBargs\fP [ \fBon\fP ] \fIarg-device\fP
+.LP
+(the ``on'' is optional.) Multiple configuration clauses
+are separated by white space;
+.I config
+allows specifications to be continued across multiple lines
+by beginning the continuation line with a tab character.
+The ``root'' clause specifies where the root file system
+is located, the ``swap'' clause indicates swapping and paging
+area(s), the ``dumps'' clause can be used to force system dumps
+to be taken on a particular device, and the ``args'' clause
+can be used to specify that argument list processing for
+.I execve
+should be done on a particular device.
+.PP
+The device names supplied in the clauses may be fully specified
+as a device, unit, and file system partition; or underspecified
+in which case
+.I config
+will use builtin rules to select default unit numbers and file
+system partitions. The defaulting rules are a bit complicated
+as they are dependent on the overall system configuration.
+For example, the swap area need not be specified at all if
+the root device is specified; in this case the swap area is
+placed in the ``b'' partition of the same disk where the root
+file system is located. Appendix B contains a complete list
+of the defaulting rules used in selecting system configuration
+devices.
+.PP
+The device names are translated to the
+appropriate major and minor device
+numbers on a per-machine basis. A file,
+``/sys/conf/devices.machine'' (where ``machine''
+is the machine type specified in the configuration file),
+is used to map a device name to its major block device number.
+The minor device number is calculated using the standard
+disk partitioning rules: on unit 0, partition ``a'' is minor device
+0, partition ``b'' is minor device 1, and so on; for units
+other than 0, add 8 times the unit number to get the minor
+device.
+.PP
+If the default mapping of device name to major/minor device
+number is incorrect for your configuration, it can be replaced
+by an explicit specification of the major/minor device.
+This is done by substituting
+.IP
+\fBmajor\fP \fIx\fP \fBminor\fP \fIy\fP
+.LP
+where the device name would normally be found. For example,
+.IP
+.nf
+\fBconfig\fP kernel \fBroot\fP \fBon\fP \fBmajor\fP 99 \fBminor\fP 1
+.fi
+.PP
+Normally, the areas configured for swap space are sized by the system
+at boot time. If a non-standard size is to be used for one
+or more swap areas (less than the full partition),
+this can also be specified. To do this, the
+device name specified for a swap area should have a ``size''
+specification appended. For example,
+.IP
+.nf
+\fBconfig\fP kernel \fBroot\fP \fBon\fP hp0 \fBswap\fP \fBon\fP hp0b \fBsize\fP 1200
+.fi
+.LP
+would force swapping to be done in partition ``b'' of ``hp0'' and
+the swap partition size would be set to 1200 sectors. A swap area
+sized larger than the associated disk partition is trimmed to the
+partition size.
+.PP
+To create a generic configuration, only the clause ``swap generic''
+should be specified; any extra clauses will cause an error.
+.NH 2
+Device specifications
+.PP
+Each device attached to a machine must be specified
+to
+.I config
+so that the system generated will know to probe for it during
+the autoconfiguration process carried out at boot time. Hardware
+specified in the configuration need not actually be present on
+the machine where the generated system is to be run. Only the
+hardware actually found at boot time will be used by the system.
+.PP
+The specification of hardware devices in the configuration file
+parallels the interconnection hierarchy of the machine to be
+configured. On the VAX, this means that a configuration file must
+indicate what MASSBUS and UNIBUS adapters are present, and to
+which \fInexi\fP they might be connected.*
+.FS
+* While VAX-11/750's and VAX-11/730 do not actually have
+nexi, the system treats them as having
+.I "simulated nexi"
+to simplify device configuration.
+.FE
+Similarly, devices
+and controllers must be indicated as possibly being connected
+to one or more adapters. A device description may provide a
+complete definition of the possible configuration parameters
+or it may leave certain parameters undefined and make the system
+probe for all the possible values. The latter allows a single
+device configuration list to match many possible physical
+configurations. For example, a disk may be indicated as present
+at UNIBUS adapter 0, or at any UNIBUS adapter which the system
+locates at boot time. The latter scheme, termed
+.IR wildcarding ,
+allows more flexibility in the physical configuration of a system;
+if a disk must be moved around for some reason, the system will
+still locate it at the alternate location.
+.PP
+A device specification takes one of the following forms:
+.IP
+.nf
+\fBmaster\fP \fIdevice-name\fP \fIdevice-info\fP
+\fBcontroller\fP \fIdevice-name\fP \fIdevice-info\fP [ \fIinterrupt-spec\fP ]
+\fBdevice\fP \fIdevice-name\fP \fIdevice-info\fP \fIinterrupt-spec\fP
+\fBdisk\fP \fIdevice-name\fP \fIdevice-info\fP
+\fBtape\fP \fIdevice-name\fP \fIdevice-info\fP
+.fi
+.LP
+A ``master'' is a MASSBUS tape controller; a ``controller'' is a
+disk controller, a UNIBUS tape controller, a MASSBUS adapter, or
+a UNIBUS adapter. A ``device'' is an autonomous device which
+connects directly to a UNIBUS adapter (as opposed to something
+like a disk which connects through a disk controller). ``Disk''
+and ``tape'' identify disk drives and tape drives connected to
+a ``controller'' or ``master.''
+.PP
+The
+.I device-name
+is one of the standard device names, as
+indicated in section 4 of the UNIX Programmers Manual,
+concatenated with the
+.I logical
+unit number to be assigned the device (the
+.I logical
+unit number may be different than the
+.I physical
+unit number indicated on the front of something
+like a disk; the
+.I logical
+unit number is used to refer to the UNIX device, not
+the physical unit number). For example, ``hp0'' is logical
+unit 0 of a MASSBUS storage device, even though it might
+be physical unit 3 on MASSBUS adapter 1.
+.PP
+The
+.I device-info
+clause specifies how the hardware is
+connected in the interconnection hierarchy. On the VAX,
+UNIBUS and MASSBUS adapters are connected to the internal
+system bus through
+a \fInexus\fP.
+Thus, one of the following
+specifications would be used:
+.IP
+.ta 1.5i 2.5i 4.0i
+.nf
+\fBcontroller\fP mba0 \fBat\fP \fBnexus\fP \fIx\fP
+\fBcontroller\fP uba0 \fBat\fP \fBnexus\fP \fIx\fP
+.fi
+.LP
+To tie a controller to a specific nexus, ``x'' would be supplied
+as the number of that nexus; otherwise ``x'' may be specified as
+``?'', in which
+case the system will probe all nexi present looking
+for the specified controller.
+.PP
+The remaining interconnections on the VAX are:
+.IP \(bu 3
+a controller
+may be connected to another controller (e.g. a disk controller attached
+to a UNIBUS adapter),
+.IP \(bu 3
+a master is always attached to a controller (a MASSBUS adapter),
+.IP \(bu 3
+a tape is always attached to a master (for MASSBUS
+tape drives),
+.IP \(bu 3
+a disk is always attached to a controller, and
+.IP \(bu 3
+devices
+are always attached to controllers (e.g. UNIBUS controllers attached
+to UNIBUS adapters).
+.LP
+The following lines give an example of each of these interconnections:
+.IP
+.ta 1.5i 2.5i 4.0i
+.nf
+\fBcontroller\fP hk0 \fBat\fP uba0 ...
+\fBmaster\fP ht0 \fBat\fP mba0 ...
+\fBdisk\fP hp0 \fBat\fP mba0 ...
+\fBtape\fP tu0 \fBat\fP ht0 ...
+\fBdisk\fP rk1 \fBat\fP hk0 ...
+\fBdevice\fP dz0 \fBat\fP uba0 ...
+.fi
+.LP
+Any piece of hardware which may be connected to a specific
+controller may also be wildcarded across multiple controllers.
+.PP
+The final piece of information needed by the system to configure
+devices is some indication of where or how a device will interrupt.
+For tapes and disks, simply specifying the \fIslave\fP or \fIdrive\fP
+number is sufficient to locate the control status register for the
+device.
+\fIDrive\fP numbers may be wildcarded
+on MASSBUS devices, but not on disks on a UNIBUS controller.
+For controllers, the control status register must be
+given explicitly, as well the number of interrupt vectors used and
+the names of the routines to which they should be bound.
+Thus the example lines given above might be completed as:
+.IP
+.ta 1.5i 2.5i 4.0i
+.nf
+\fBcontroller\fP hk0 \fBat\fP uba0 \fBcsr\fP 0177440 \fBvector\fP rkintr
+\fBmaster\fP ht0 \fBat\fP mba0 \fBdrive\fP 0
+\fBdisk\fP hp0 \fBat\fP mba0 \fBdrive\fP ?
+\fBtape\fP tu0 \fBat\fP ht0 \fBslave\fP 0
+\fBdisk\fP rk1 \fBat\fP hk0 \fBdrive\fP 1
+\fBdevice\fP dz0 \fBat\fP uba0 \fBcsr\fP 0160100 \fBvector\fP dzrint dzxint
+.fi
+.PP
+Certain device drivers require extra information passed to them
+at boot time to tailor their operation to the actual hardware present.
+The line printer driver, for example, needs to know how many columns
+are present on each non-standard line printer (i.e. a line printer
+with other than 80 columns). The drivers for the terminal multiplexors
+need to know which lines are attached to modem lines so that no one will
+be allowed to use them unless a connection is present. For this reason,
+one last parameter may be specified to a
+.IR device ,
+a
+.I flags
+field. It has the syntax
+.IP
+\fBflags\fP \fInumber\fP
+.LP
+and is usually placed after the
+.I csr
+specification. The
+.I number
+is passed directly to the associated driver. The manual pages
+in section 4 should be consulted to determine how each driver
+uses this value (if at all).
+Communications interface drivers commonly use the flags
+to indicate whether modem control signals are in use.
+.PP
+The exact syntax for each specific device is given in the Synopsis
+section of its manual page in section 4 of the manual.
+.NH 2
+Pseudo-devices
+.PP
+A number of drivers and software subsystems
+are treated like device drivers without any associated hardware.
+To include any of these pieces, a ``pseudo-device'' specification
+must be used. A specification for a pseudo device takes the form
+.IP
+.DT
+.nf
+\fBpseudo-device\fP \fIdevice-name\fP [ \fIhowmany\fP ]
+.fi
+.PP
+Examples of pseudo devices are
+\fBpty\fP, the pseudo terminal driver (where the optional
+.I howmany
+value indicates the number of pseudo terminals to configure, 32 default),
+and \fBloop\fP, the software loopback network pseudo-interface.
+Other pseudo devices for the network include
+\fBimp\fP (required when a CSS or ACC imp is configured)
+and \fBether\fP (used by the Address Resolution Protocol
+on 10 Mb/sec Ethernets).
+More information on configuring each of these can also be found
+in section 4 of the manual.
diff --git a/usr.sbin/config/SMM.doc/5.t b/usr.sbin/config/SMM.doc/5.t
new file mode 100644
index 0000000..81f2a52
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/5.t
@@ -0,0 +1,271 @@
+.\" 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
+.\"
+.\".ds RH "Sample Configuration Files
+.ne 2i
+.NH
+SAMPLE CONFIGURATION FILES
+.PP
+In this section we will consider how to configure a
+sample VAX-11/780 system on which the hardware can be
+reconfigured to guard against various hardware mishaps.
+We then study the rules needed to configure a VAX-11/750
+to run in a networking environment.
+.NH 2
+VAX-11/780 System
+.PP
+Our VAX-11/780 is configured with hardware
+recommended in the document ``Hints on Configuring a VAX for 4.2BSD''
+(this is one of the high-end configurations).
+Table 1 lists the pertinent hardware to be configured.
+.DS B
+.TS
+box;
+l | l | l | l | l
+l | l | l | l | l.
+Item Vendor Connection Name Reference
+_
+cpu DEC VAX780
+MASSBUS controller Emulex nexus ? mba0 hp(4)
+disk Fujitsu mba0 hp0
+disk Fujitsu mba0 hp1
+MASSBUS controller Emulex nexus ? mba1
+disk Fujitsu mba1 hp2
+disk Fujitsu mba1 hp3
+UNIBUS adapter DEC nexus ?
+tape controller Emulex uba0 tm0 tm(4)
+tape drive Kennedy tm0 te0
+tape drive Kennedy tm0 te1
+terminal multiplexor Emulex uba0 dh0 dh(4)
+terminal multiplexor Emulex uba0 dh1
+terminal multiplexor Emulex uba0 dh2
+.TE
+.DE
+.ce
+Table 1. VAX-11/780 Hardware support.
+.LP
+We will call this machine ANSEL and construct a configuration
+file one step at a time.
+.PP
+The first step is to fill in the global configuration parameters.
+The machine is a VAX, so the
+.I "machine type"
+is ``vax''. We will assume this system will
+run only on this one processor, so the
+.I "cpu type"
+is ``VAX780''. The options are empty since this is going to
+be a ``vanilla'' VAX. The system identifier, as mentioned before,
+is ``ANSEL,'' and the maximum number of users we plan to support is
+about 40. Thus the beginning of the configuration file looks like
+this:
+.DS
+.ta 1.5i 2.5i 4.0i
+#
+# ANSEL VAX (a picture perfect machine)
+#
+machine vax
+cpu VAX780
+timezone 8 dst
+ident ANSEL
+maxusers 40
+.DE
+.PP
+To this we must then add the specifications for three
+system images. The first will be our standard system with the
+root on ``hp0'' and swapping on the same drive as the root.
+The second will have the root file system in the same location,
+but swap space interleaved among drives on each controller.
+Finally, the third will be a generic system,
+to allow us to boot off any of the four disk drives.
+.DS
+.ta 1.5i 2.5i
+config kernel root on hp0
+config hpkernel root on hp0 swap on hp0 and hp2
+config genkernel swap generic
+.DE
+.PP
+Finally, the hardware must be specified. Let us first just try
+transcribing the information from Table 1.
+.DS
+.ta 1.5i 2.5i 4.0i
+controller mba0 at nexus ?
+disk hp0 at mba0 disk 0
+disk hp1 at mba0 disk 1
+controller mba1 at nexus ?
+disk hp2 at mba1 disk 2
+disk hp3 at mba1 disk 3
+controller uba0 at nexus ?
+controller tm0 at uba0 csr 0172520 vector tmintr
+tape te0 at tm0 drive 0
+tape te1 at tm0 drive 1
+device dh0 at uba0 csr 0160020 vector dhrint dhxint
+device dm0 at uba0 csr 0170500 vector dmintr
+device dh1 at uba0 csr 0160040 vector dhrint dhxint
+device dh2 at uba0 csr 0160060 vector dhrint dhxint
+.DE
+.LP
+(Oh, I forgot to mention one panel of the terminal multiplexor
+has modem control, thus the ``dm0'' device.)
+.PP
+This will suffice, but leaves us with little flexibility. Suppose
+our first disk controller were to break. We would like to recable the
+drives normally on the second controller so that all our disks could
+still be used without reconfiguring the system. To do this we wildcard
+the MASSBUS adapter connections and also the slave numbers. Further,
+we wildcard the UNIBUS adapter connections in case we decide some time
+in the future to purchase another adapter to offload the single UNIBUS
+we currently have. The revised device specifications would then be:
+.DS
+.ta 1.5i 2.5i 4.0i
+controller mba0 at nexus ?
+disk hp0 at mba? disk ?
+disk hp1 at mba? disk ?
+controller mba1 at nexus ?
+disk hp2 at mba? disk ?
+disk hp3 at mba? disk ?
+controller uba0 at nexus ?
+controller tm0 at uba? csr 0172520 vector tmintr
+tape te0 at tm0 drive 0
+tape te1 at tm0 drive 1
+device dh0 at uba? csr 0160020 vector dhrint dhxint
+device dm0 at uba? csr 0170500 vector dmintr
+device dh1 at uba? csr 0160040 vector dhrint dhxint
+device dh2 at uba? csr 0160060 vector dhrint dhxint
+.DE
+.LP
+The completed configuration file for ANSEL is shown in Appendix C.
+.NH 2
+VAX-11/750 with network support
+.PP
+Our VAX-11/750 system will be located on two 10Mb/s Ethernet
+local area networks and also the DARPA Internet. The system
+will have a MASSBUS drive for the root file system and two
+UNIBUS drives. Paging is interleaved among all three drives.
+We have sold our standard DEC terminal multiplexors since this
+machine will be accessed solely through the network. This
+machine is not intended to have a large user community, it
+does not have a great deal of memory. First the global parameters:
+.DS
+.ta 1.5i 2.5i 4.0i
+#
+# UCBVAX (Gateway to the world)
+#
+machine vax
+cpu "VAX780"
+cpu "VAX750"
+ident UCBVAX
+timezone 8 dst
+maxusers 32
+options INET
+options NS
+.DE
+.PP
+The multiple cpu types allow us to replace UCBVAX with a
+more powerful cpu without reconfiguring the system. The
+value of 32 given for the maximum number of users is done to
+force the system data structures to be over-allocated. That
+is desirable on this machine because, while it is not expected
+to support many users, it is expected to perform a great deal
+of work.
+The ``INET'' indicates that we plan to use the
+DARPA standard Internet protocols on this machine,
+and ``NS'' also includes support for Xerox NS protocols.
+Note that unlike 4.2BSD configuration files,
+the network protocol options do not require corresponding pseudo devices.
+.PP
+The system images and disks are configured next.
+.DS
+.ta 1.5i 2.5i 4.0i
+config kernel root on hp swap on hp and rk0 and rk1
+config upkernel root on up
+config hkkernel root on hk swap on rk0 and rk1
+
+controller mba0 at nexus ?
+controller uba0 at nexus ?
+disk hp0 at mba? drive 0
+disk hp1 at mba? drive 1
+controller sc0 at uba? csr 0176700 vector upintr
+disk up0 at sc0 drive 0
+disk up1 at sc0 drive 1
+controller hk0 at uba? csr 0177440 vector rkintr
+disk rk0 at hk0 drive 0
+disk rk1 at hk0 drive 1
+.DE
+.PP
+UCBVAX requires heavy interleaving of its paging area to keep up
+with all the mail traffic it handles. The limiting factor on this
+system's performance is usually the number of disk arms, as opposed
+to memory or cpu cycles. The extra UNIBUS controller, ``sc0'',
+is in case the MASSBUS controller breaks and a spare controller
+must be installed (most of our old UNIBUS controllers have been
+replaced with the newer MASSBUS controllers, so we have a number
+of these around as spares).
+.PP
+Finally, we add in the network devices.
+Pseudo terminals are needed to allow users to
+log in across the network (remember the only hardwired terminal
+is the console).
+The software loopback device is used for on-machine communications.
+The connection to the Internet is through
+an IMP, this requires yet another
+.I pseudo-device
+(in addition to the actual hardware device used by the
+IMP software). And, finally, there are the two Ethernet devices.
+These use a special protocol, the Address Resolution Protocol (ARP),
+to map between Internet and Ethernet addresses. Thus, yet another
+.I pseudo-device
+is needed. The additional device specifications are show below.
+.DS
+.ta 1.5i 2.5i 4.0i
+pseudo-device pty
+pseudo-device loop
+pseudo-device imp
+device acc0 at uba? csr 0167600 vector accrint accxint
+pseudo-device ether
+device ec0 at uba? csr 0164330 vector ecrint eccollide ecxint
+device il0 at uba? csr 0164000 vector ilrint ilcint
+.DE
+.LP
+The completed configuration file for UCBVAX is shown in Appendix C.
+.NH 2
+Miscellaneous comments
+.PP
+It should be noted in these examples that neither system was
+configured to use disk quotas or the 4.1BSD compatibility mode.
+To use these optional facilities, and others, we would probably
+clean out our current configuration, reconfigure the system, then
+recompile and relink the system image(s). This could, of course,
+be avoided by figuring out which relocatable object files are
+affected by the reconfiguration, then reconfiguring and recompiling
+only those files affected by the configuration change. This technique
+should be used carefully.
diff --git a/usr.sbin/config/SMM.doc/6.t b/usr.sbin/config/SMM.doc/6.t
new file mode 100644
index 0000000..f02baed
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/6.t
@@ -0,0 +1,239 @@
+.\" 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
+.\"
+.\".ds RH "Adding New Devices
+.ne 2i
+.NH
+ADDING NEW SYSTEM SOFTWARE
+.PP
+This section is not for the novice, it describes
+some of the inner workings of the configuration process as
+well as the pertinent parts of the system autoconfiguration process.
+It is intended to give
+those people who intend to install new device drivers and/or
+other system facilities sufficient information to do so in the
+manner which will allow others to easily share the changes.
+.PP
+This section is broken into four parts:
+.IP \(bu 3
+general guidelines to be followed in modifying system code,
+.IP \(bu 3
+how to add non-standard system facilities to 4.4BSD,
+.IP \(bu 3
+how to add a device driver to 4.4BSD, and
+.NH 2
+Modifying system code
+.PP
+If you wish to make site-specific modifications to the system
+it is best to bracket them with
+.DS
+#ifdef SITENAME
+\&...
+#endif
+.DE
+to allow your source to be easily distributed to others, and
+also to simplify \fIdiff\fP\|(1) listings. If you choose not
+to use a source code control system (e.g. SCCS, RCS), and
+perhaps even if you do, it is
+recommended that you save the old code with something
+of the form:
+.DS
+#ifndef SITENAME
+\&...
+#endif
+.DE
+We try to isolate our site-dependent code in individual files
+which may be configured with pseudo-device specifications.
+.PP
+Indicate machine-specific code with ``#ifdef vax'' (or other machine,
+as appropriate).
+4.4BSD underwent extensive work to make it extremely portable to
+machines with similar architectures\- you may someday find
+yourself trying to use a single copy of the source code on
+multiple machines.
+.NH 2
+Adding non-standard system facilities
+.PP
+This section considers the work needed to augment
+.IR config 's
+data base files for non-standard system facilities.
+.I Config
+uses a set of files that list the source modules that may be required
+when building a system.
+The data bases are taken from the directory in which
+.I config
+is run, normally /sys/conf.
+Three such files may be used:
+.IR files ,
+.IR files .machine,
+and
+.IR files .ident.
+The first is common to all systems,
+the second contains files unique to a single machine type,
+and the third is an optional list of modules for use on a specific machine.
+This last file may override specifications in the first two.
+The format of the
+.I files
+file has grown somewhat complex over time. Entries are normally of
+the form
+.IP
+.nf
+.DT
+\fIdir/source.c\fP \fItype\fP \fIoption-list\fP \fImodifiers\fP
+.LP
+for example,
+.IP
+.nf
+.DT
+\fIvaxuba/foo.c\fP \fBoptional\fP foo \fBdevice-driver\fP
+.LP
+The
+.I type
+is one of
+.B standard
+or
+.BR optional .
+Files marked as standard are included in all system configurations.
+Optional file specifications include a list of one or more system
+options that together require the inclusion of this module.
+The options in the list may be either names of devices that may
+be in the configuration file,
+or the names of system options that may be defined.
+An optional file may be listed multiple times with different options;
+if all of the options for any of the entries are satisfied,
+the module is included.
+.PP
+If a file is specified as a
+.IR device-driver ,
+any special compilation options for device drivers will be invoked.
+On the VAX this results in the use of the
+.B \-i
+option for the C optimizer. This is required when pointer references
+are made to memory locations in the VAX I/O address space.
+.PP
+Two other optional keywords modify the usage of the file.
+.I Config
+understands that certain files are used especially for
+kernel profiling. These files are indicated in the
+.I files
+files with a
+.I profiling-routine
+keyword. For example, the current profiling subroutines
+are sequestered off in a separate file with the following
+entry:
+.IP
+.nf
+.DT
+\fIsys/subr_mcount.c\fP \fBoptional\fP \fBprofiling-routine\fP
+.fi
+.LP
+The
+.I profiling-routine
+keyword forces
+.I config
+not to compile the source file with the
+.B \-pg
+option.
+.PP
+The second keyword which can be of use is the
+.I config-dependent
+keyword. This causes
+.I config
+to compile the indicated module with the global configuration
+parameters. This allows certain modules, such as
+.I machdep.c
+to size system data structures based on the maximum number
+of users configured for the system.
+.NH 2
+Adding device drivers to 4.4BSD
+.PP
+The I/O system and
+.I config
+have been designed to easily allow new device support to be added.
+The system source directories are organized as follows:
+.DS
+.TS
+lw(1.0i) l.
+/sys/h machine independent include files
+/sys/sys machine-independent system source files
+/sys/conf site configuration files and basic templates
+/sys/net network-protocol-independent, but network-related code
+/sys/netinet DARPA Internet code
+/sys/netimp IMP support code
+/sys/netns Xerox NS code
+/sys/vax VAX-specific mainline code
+/sys/vaxif VAX network interface code
+/sys/vaxmba VAX MASSBUS device drivers and related code
+/sys/vaxuba VAX UNIBUS device drivers and related code
+.TE
+.DE
+.PP
+Existing block and character device drivers for the VAX
+reside in ``/sys/vax'', ``/sys/vaxmba'', and ``/sys/vaxuba''. Network
+interface drivers reside in ``/sys/vaxif''. Any new device
+drivers should be placed in the appropriate source code directory
+and named so as not to conflict with existing devices.
+Normally, definitions for things like device registers are placed in
+a separate file in the same directory. For example, the ``dh''
+device driver is named ``dh.c'' and its associated include file is
+named ``dhreg.h''.
+.PP
+Once the source for the device driver has been placed in a directory,
+the file ``/sys/conf/files.machine'', and possibly
+``/sys/conf/devices.machine'' should be modified. The
+.I files
+files in the conf directory contain a line for each C source or binary-only
+file in the system. Those files which are machine independent are
+located in ``/sys/conf/files,'' while machine specific files
+are in ``/sys/conf/files.machine.'' The ``devices.machine'' file
+is used to map device names to major block device numbers. If the device
+driver being added provides support for a new disk
+you will want to modify this file (the format is obvious).
+.PP
+In addition to including the driver in the
+.I files
+file, it must also be added to the device configuration tables. These
+are located in ``/sys/vax/conf.c'', or similar for machines other than
+the VAX. If you don't understand what to add to this file, you should
+study an entry for an existing driver.
+Remember that the position in the
+device table specifies the major device number.
+The block major number is needed in the ``devices.machine'' file
+if the device is a disk.
+.PP
+With the configuration information in place, your configuration
+file appropriately modified, and a system reconfigured and rebooted
+you should incorporate the shell commands needed to install the special
+files in the file system to the file ``/dev/MAKEDEV'' or
+``/dev/MAKEDEV.local''. This is discussed in the document ``Installing
+and Operating 4.4BSD''.
diff --git a/usr.sbin/config/SMM.doc/Makefile b/usr.sbin/config/SMM.doc/Makefile
new file mode 100644
index 0000000..3a2f188
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/Makefile
@@ -0,0 +1,10 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/02.config
+SRCS= 0.t 1.t 2.t 3.t 4.t 5.t 6.t a.t b.t c.t d.t e.t
+MACROS= -ms
+
+paper.ps: ${SRCS}
+ ${TBL} ${SRCS} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/config/SMM.doc/a.t b/usr.sbin/config/SMM.doc/a.t
new file mode 100644
index 0000000..dfcb954
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/a.t
@@ -0,0 +1,162 @@
+.\" 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.
+.\"
+.\" @(#)a.t 8.1 (Berkeley) 6/8/93
+.\"
+.\".ds RH "Configuration File Grammar
+.bp
+.LG
+.B
+.ce
+APPENDIX A. CONFIGURATION FILE GRAMMAR
+.sp
+.R
+.NL
+.PP
+The following grammar is a compressed form of the actual
+\fIyacc\fP\|(1) grammar used by
+.I config
+to parse configuration files.
+Terminal symbols are shown all in upper case, literals
+are emboldened; optional clauses are enclosed in brackets, ``[''
+and ``]''; zero or more instantiations are denoted with ``*''.
+.sp
+.nf
+.DT
+Configuration ::= [ Spec \fB;\fP ]*
+
+Spec ::= Config_spec
+ | Device_spec
+ | \fBtrace\fP
+ | /* lambda */
+
+/* configuration specifications */
+
+Config_spec ::= \fBmachine\fP ID
+ | \fBcpu\fP ID
+ | \fBoptions\fP Opt_list
+ | \fBident\fP ID
+ | System_spec
+ | \fBtimezone\fP [ \fB\-\fP ] NUMBER [ \fBdst\fP [ NUMBER ] ]
+ | \fBtimezone\fP [ \fB\-\fP ] FPNUMBER [ \fBdst\fP [ NUMBER ] ]
+ | \fBmaxusers\fP NUMBER
+
+/* system configuration specifications */
+
+System_spec ::= \fBconfig\fP ID System_parameter [ System_parameter ]*
+
+System_parameter ::= swap_spec | root_spec | dump_spec | arg_spec
+
+swap_spec ::= \fBswap\fP [ \fBon\fP ] swap_dev [ \fBand\fP swap_dev ]*
+
+swap_dev ::= dev_spec [ \fBsize\fP NUMBER ]
+
+root_spec ::= \fBroot\fP [ \fBon\fP ] dev_spec
+
+dump_spec ::= \fBdumps\fP [ \fBon\fP ] dev_spec
+
+arg_spec ::= \fBargs\fP [ \fBon\fP ] dev_spec
+
+dev_spec ::= dev_name | major_minor
+
+major_minor ::= \fBmajor\fP NUMBER \fBminor\fP NUMBER
+
+dev_name ::= ID [ NUMBER [ ID ] ]
+
+/* option specifications */
+
+Opt_list ::= Option [ \fB,\fP Option ]*
+
+Option ::= ID [ \fB=\fP Opt_value ]
+
+Opt_value ::= ID | NUMBER
+
+Mkopt_list ::= Mkoption [ \fB,\fP Mkoption ]*
+
+Mkoption ::= ID \fB=\fP Opt_value
+
+/* device specifications */
+
+Device_spec ::= \fBdevice\fP Dev_name Dev_info Int_spec
+ | \fBmaster\fP Dev_name Dev_info
+ | \fBdisk\fP Dev_name Dev_info
+ | \fBtape\fP Dev_name Dev_info
+ | \fBcontroller\fP Dev_name Dev_info [ Int_spec ]
+ | \fBpseudo-device\fP Dev [ NUMBER ]
+
+Dev_name ::= Dev NUMBER
+
+Dev ::= \fBuba\fP | \fBmba\fP | ID
+
+Dev_info ::= Con_info [ Info ]*
+
+Con_info ::= \fBat\fP Dev NUMBER
+ | \fBat\fP \fBnexus\fP NUMBER
+
+Info ::= \fBcsr\fP NUMBER
+ | \fBdrive\fP NUMBER
+ | \fBslave\fP NUMBER
+ | \fBflags\fP NUMBER
+
+Int_spec ::= \fBvector\fP ID [ ID ]*
+ | \fBpriority\fP NUMBER
+.fi
+.sp
+.SH
+Lexical Conventions
+.LP
+The terminal symbols are loosely defined as:
+.IP ID
+.br
+One or more alphabetics, either upper or lower case, and underscore,
+``_''.
+.IP NUMBER
+.br
+Approximately the C language specification for an integer number.
+That is, a leading ``0x'' indicates a hexadecimal value,
+a leading ``0'' indicates an octal value, otherwise the number is
+expected to be a decimal value. Hexadecimal numbers may use either
+upper or lower case alphabetics.
+.IP FPNUMBER
+.br
+A floating point number without exponent. That is a number of the
+form ``nnn.ddd'', where the fractional component is optional.
+.LP
+In special instances a question mark, ``?'', can be substituted for
+a ``NUMBER'' token. This is used to effect wildcarding in device
+interconnection specifications.
+.LP
+Comments in configuration files are indicated by a ``#'' character
+at the beginning of the line; the remainder of the line is discarded.
+.LP
+A specification
+is interpreted as a continuation of the previous line
+if the first character of the line is tab.
diff --git a/usr.sbin/config/SMM.doc/b.t b/usr.sbin/config/SMM.doc/b.t
new file mode 100644
index 0000000..901a009
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/b.t
@@ -0,0 +1,137 @@
+.\" 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.
+.\"
+.\" @(#)b.t 8.1 (Berkeley) 6/8/93
+.\"
+.\".ds RH "Device Defaulting Rules
+.bp
+.LG
+.B
+.ce
+APPENDIX B. RULES FOR DEFAULTING SYSTEM DEVICES
+.sp
+.R
+.NL
+.PP
+When \fIconfig\fP processes a ``config'' rule which does
+not fully specify the location of the root file system,
+paging area(s), device for system dumps, and device for
+argument list processing it applies a set of rules to
+define those values left unspecified. The following list
+of rules are used in defaulting system devices.
+.IP 1) 3
+If a root device is not specified, the swap
+specification must indicate a ``generic'' system is to be built.
+.IP 2) 3
+If the root device does not specify a unit number, it
+defaults to unit 0.
+.IP 3) 3
+If the root device does not include a partition specification,
+it defaults to the ``a'' partition.
+.IP 4) 3
+If no swap area is specified, it defaults to the ``b''
+partition of the root device.
+.IP 5) 3
+If no device is specified for processing argument lists, the
+first swap partition is selected.
+.IP 6) 3
+If no device is chosen for system dumps, the first swap
+partition is selected (see below to find out where dumps are
+placed within the partition).
+.PP
+The following table summarizes the default partitions selected
+when a device specification is incomplete, e.g. ``hp0''.
+.DS
+.TS
+l l.
+Type Partition
+_
+root ``a''
+swap ``b''
+args ``b''
+dumps ``b''
+.TE
+.DE
+.SH
+Multiple swap/paging areas
+.PP
+When multiple swap partitions are specified, the system treats the
+first specified as a ``primary'' swap area which is always used.
+The remaining partitions are then interleaved into the paging
+system at the time a
+.IR swapon (2)
+system call is made. This is normally done at boot time with
+a call to
+.IR swapon (8)
+from the /etc/rc file.
+.SH
+System dumps
+.PP
+System dumps are automatically taken after a system crash,
+provided the device driver for the ``dumps'' device supports
+this. The dump contains the contents of memory, but not
+the swap areas. Normally the dump device is a disk in
+which case the information is copied to a location at the
+back of the partition. The dump is placed in the back of the
+partition because the primary swap and dump device are commonly
+the same device and this allows the system to be rebooted without
+immediately overwriting the saved information. When a dump has
+occurred, the system variable \fIdumpsize\fP
+is set to a non-zero value indicating the size (in bytes) of
+the dump. The \fIsavecore\fP\|(8)
+program then copies the information from the dump partition to
+a file in a ``crash'' directory and also makes a copy of the
+system which was running at the time of the crash (usually
+``/kernel''). The offset to the system dump is defined in the
+system variable \fIdumplo\fP (a sector offset from
+the front of the dump partition). The
+.I savecore
+program operates by reading the contents of \fIdumplo\fP, \fIdumpdev\fP,
+and \fIdumpmagic\fP from /dev/kmem, then comparing the value
+of \fIdumpmagic\fP read from /dev/kmem to that located in
+corresponding location in the dump area of the dump partition.
+If a match is found,
+.I savecore
+assumes a crash occurred and reads \fIdumpsize\fP from the dump area
+of the dump partition. This value is then used in copying the
+system dump. Refer to
+\fIsavecore\fP\|(8)
+for more information about its operation.
+.PP
+The value \fIdumplo\fP is calculated to be
+.DS
+\fIdumpdev-size\fP \- \fImemsize\fP
+.DE
+where \fIdumpdev-size\fP is the size of the disk partition
+where system dumps are to be placed, and
+\fImemsize\fP is the size of physical memory.
+If the disk partition is not large enough to hold a full
+dump, \fIdumplo\fP is set to 0 (the start of the partition).
diff --git a/usr.sbin/config/SMM.doc/c.t b/usr.sbin/config/SMM.doc/c.t
new file mode 100644
index 0000000..67b63ec
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/c.t
@@ -0,0 +1,109 @@
+.\" 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.
+.\"
+.\" @(#)c.t 8.1 (Berkeley) 6/8/93
+.\"
+.\".ds RH "Sample Config Files
+.bp
+.LG
+.B
+.ce
+APPENDIX C. SAMPLE CONFIGURATION FILES
+.sp
+.R
+.NL
+.PP
+The following configuration files are developed in section 5;
+they are included here for completeness.
+.sp 2
+.nf
+.ta 1.5i 2.5i 4.0i
+#
+# ANSEL VAX (a picture perfect machine)
+#
+machine vax
+cpu VAX780
+timezone 8 dst
+ident ANSEL
+maxusers 40
+
+config kernel root on hp0
+config hpkernel root on hp0 swap on hp0 and hp2
+config genkernel swap generic
+
+controller mba0 at nexus ?
+disk hp0 at mba? disk ?
+disk hp1 at mba? disk ?
+controller mba1 at nexus ?
+disk hp2 at mba? disk ?
+disk hp3 at mba? disk ?
+controller uba0 at nexus ?
+controller tm0 at uba? csr 0172520 vector tmintr
+tape te0 at tm0 drive 0
+tape te1 at tm0 drive 1
+device dh0 at uba? csr 0160020 vector dhrint dhxint
+device dm0 at uba? csr 0170500 vector dmintr
+device dh1 at uba? csr 0160040 vector dhrint dhxint
+device dh2 at uba? csr 0160060 vector dhrint dhxint
+.bp
+#
+# UCBVAX - Gateway to the world
+#
+machine vax
+cpu "VAX780"
+cpu "VAX750"
+ident UCBVAX
+timezone 8 dst
+maxusers 32
+options INET
+options NS
+
+config kernel root on hp swap on hp and rk0 and rk1
+config upkernel root on up
+config hkkernel root on hk swap on rk0 and rk1
+
+controller mba0 at nexus ?
+controller uba0 at nexus ?
+disk hp0 at mba? drive 0
+disk hp1 at mba? drive 1
+controller sc0 at uba? csr 0176700 vector upintr
+disk up0 at sc0 drive 0
+disk up1 at sc0 drive 1
+controller hk0 at uba? csr 0177440 vector rkintr
+disk rk0 at hk0 drive 0
+disk rk1 at hk0 drive 1
+pseudo-device pty
+pseudo-device loop
+pseudo-device imp
+device acc0 at uba? csr 0167600 vector accrint accxint
+pseudo-device ether
+device ec0 at uba? csr 0164330 vector ecrint eccollide ecxint
+device il0 at uba? csr 0164000 vector ilrint ilcint
diff --git a/usr.sbin/config/SMM.doc/d.t b/usr.sbin/config/SMM.doc/d.t
new file mode 100644
index 0000000..db9ab80
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/d.t
@@ -0,0 +1,272 @@
+.\" 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.
+.\"
+.\" @(#)d.t 8.1 (Berkeley) 6/8/93
+.\"
+.\".ds RH "Data Structure Sizing Rules
+.bp
+.LG
+.B
+.ce
+APPENDIX D. VAX KERNEL DATA STRUCTURE SIZING RULES
+.sp
+.R
+.NL
+.PP
+Certain system data structures are sized at compile time
+according to the maximum number of simultaneous users expected,
+while others are calculated at boot time based on the
+physical resources present, e.g. memory. This appendix lists
+both sets of rules and also includes some hints on changing
+built-in limitations on certain data structures.
+.SH
+Compile time rules
+.PP
+The file \fI/sys/conf\|/param.c\fP contains the definitions of
+almost all data structures sized at compile time. This file
+is copied into the directory of each configured system to allow
+configuration-dependent rules and values to be maintained.
+(Each copy normally depends on the copy in /sys/conf,
+and global modifications cause the file to be recopied unless
+the makefile is modified.)
+The rules implied by its contents are summarized below (here
+MAXUSERS refers to the value defined in the configuration file
+in the ``maxusers'' rule).
+Most limits are computed at compile time and stored in global variables
+for use by other modules; they may generally be patched in the system
+binary image before rebooting to test new values.
+.IP \fBnproc\fP
+.br
+The maximum number of processes which may be running at any time.
+It is referred to in other calculations as NPROC and is defined to be
+.DS
+20 + 8 * MAXUSERS
+.DE
+.IP \fBntext\fP
+.br
+The maximum number of active shared text segments.
+The constant is intended to allow for network servers and common commands
+that remain in the table.
+It is defined as
+.DS
+36 + MAXUSERS.
+.DE
+.IP \fBninode\fP
+.br
+The maximum number of files in the file system which may be
+active at any time. This includes files in use by users, as
+well as directory files being read or written by the system
+and files associated with bound sockets in the UNIX IPC domain.
+It is defined as
+.DS
+(NPROC + 16 + MAXUSERS) + 32
+.DE
+.IP \fBnfile\fP
+.br
+The number of ``file table'' structures. One file
+table structure is used for each open, unshared, file descriptor.
+Multiple file descriptors may reference a single file table
+entry when they are created through a \fIdup\fP call, or as the
+result of a \fIfork\fP. This is defined to be
+.DS
+16 * (NPROC + 16 + MAXUSERS) / 10 + 32
+.DE
+.IP \fBncallout\fP
+.br
+The number of ``callout'' structures. One callout
+structure is used per internal system event handled with
+a timeout. Timeouts are used for terminal delays,
+watchdog routines in device drivers, protocol timeout processing, etc.
+This is defined as
+.DS
+16 + NPROC
+.DE
+.IP \fBnclist\fP
+.br
+The number of ``c-list'' structures. C-list structures are
+used in terminal I/O, and currently each holds 60 characters.
+Their number is defined as
+.DS
+60 + 12 * MAXUSERS
+.DE
+.IP \fBnmbclusters\fP
+.br
+The maximum number of pages which may be allocated by the network.
+This is defined as 256 (a quarter megabyte of memory) in /sys/h/mbuf.h.
+In practice, the network rarely uses this much memory. It starts off
+by allocating 8 kilobytes of memory, then requesting more as
+required. This value represents an upper bound.
+.IP \fBnquota\fP
+.br
+The number of ``quota'' structures allocated. Quota structures
+are present only when disc quotas are configured in the system. One
+quota structure is kept per user. This is defined to be
+.DS
+(MAXUSERS * 9) / 7 + 3
+.DE
+.IP \fBndquot\fP
+.br
+The number of ``dquot'' structures allocated. Dquot structures
+are present only when disc quotas are configured in the system.
+One dquot structure is required per user, per active file system quota.
+That is, when a user manipulates a file on a file system on which
+quotas are enabled, the information regarding the user's quotas on
+that file system must be in-core. This information is cached, so
+that not all information must be present in-core all the time.
+This is defined as
+.DS
+NINODE + (MAXUSERS * NMOUNT) / 4
+.DE
+where NMOUNT is the maximum number of mountable file systems.
+.LP
+In addition to the above values, the system page tables (used to
+map virtual memory in the kernel's address space) are sized at
+compile time by the SYSPTSIZE definition in the file /sys/vax/vmparam.h.
+This is defined to be
+.DS
+20 + MAXUSERS
+.DE
+pages of page tables.
+Its definition affects
+the size of many data structures allocated at boot time because
+it constrains the amount of virtual memory which may be addressed
+by the running system. This is often the limiting factor
+in the size of the buffer cache, in which case a message is printed
+when the system configures at boot time.
+.SH
+Run-time calculations
+.PP
+The most important data structures sized at run-time are those used in
+the buffer cache. Allocation is done by allocating physical memory
+(and system virtual memory) immediately after the system
+has been started up; look in the file /sys/vax/machdep.c.
+The amount of physical memory which may be allocated to the buffer
+cache is constrained by the size of the system page tables, among
+other things. While the system may calculate
+a large amount of memory to be allocated to the buffer cache,
+if the system page
+table is too small to map this physical
+memory into the virtual address space
+of the system, only as much as can be mapped will be used.
+.PP
+The buffer cache is comprised of a number of ``buffer headers''
+and a pool of pages attached to these headers. Buffer headers
+are divided into two categories: those used for swapping and
+paging, and those used for normal file I/O. The system tries
+to allocate 10% of the first two megabytes and 5% of the remaining
+available physical memory for the buffer
+cache (where \fIavailable\fP does not count that space occupied by
+the system's text and data segments). If this results in fewer
+than 16 pages of memory allocated, then 16 pages are allocated.
+This value is kept in the initialized variable \fIbufpages\fP
+so that it may be patched in the binary image (to allow tuning
+without recompiling the system),
+or the default may be overridden with a configuration-file option.
+For example, the option \fBoptions BUFPAGES="3200"\fP
+causes 3200 pages (3.2M bytes) to be used by the buffer cache.
+A sufficient number of file I/O buffer headers are then allocated
+to allow each to hold 2 pages each.
+Each buffer maps 8K bytes.
+If the number of buffer pages is larger than can be mapped
+by the buffer headers, the number of pages is reduced.
+The number of buffer headers allocated
+is stored in the global variable \fInbuf\fP,
+which may be patched before the system is booted.
+The system option \fBoptions NBUF="1000"\fP forces the allocation
+of 1000 buffer headers.
+Half as many swap I/O buffer headers as file I/O buffers
+are allocated,
+but no more than 256.
+.SH
+System size limitations
+.PP
+As distributed, the sum of the virtual sizes of the core-resident
+processes is limited to 256M bytes. The size of the text
+segment of a single process is currently limited to 6M bytes.
+It may be increased to no greater than the data segment size limit
+(see below) by redefining MAXTSIZ.
+This may be done with a configuration file option,
+e.g. \fBoptions MAXTSIZ="(10*1024*1024)"\fP
+to set the limit to 10 million bytes.
+Other per-process limits discussed here may be changed with similar options
+with names given in parentheses.
+Soft, user-changeable limits are set to 512K bytes for stack (DFLSSIZ)
+and 6M bytes for the data segment (DFLDSIZ) by default;
+these may be increased up to the hard limit
+with the \fIsetrlimit\fP\|(2) system call.
+The data and stack segment size hard limits are set by a system configuration
+option to one of 17M, 33M or 64M bytes.
+One of these sizes is chosen based on the definition of MAXDSIZ;
+with no option, the limit is 17M bytes; with an option
+\fBoptions MAXDSIZ="(32*1024*1024)"\fP (or any value between 17M and 33M),
+the limit is increased to 33M bytes, and values larger than 33M
+result in a limit of 64M bytes.
+You must be careful in doing this that you have adequate paging space.
+As normally configured , the system has 16M or 32M bytes per paging area,
+depending on disk size.
+The best way to get more space is to provide multiple, thereby
+interleaved, paging areas.
+Increasing the virtual memory limits results in interleaving of
+swap space in larger sections (from 500K bytes to 1M or 2M bytes).
+.PP
+By default, the virtual memory system allocates enough memory
+for system page tables mapping user page tables
+to allow 256 megabytes of simultaneous active virtual memory.
+That is, the sum of the virtual memory sizes of all (completely- or partially-)
+resident processes can not exceed this limit.
+If the limit is exceeded, some process(es) must be swapped out.
+To increase the amount of resident virtual space possible,
+you can alter the constant USRPTSIZE (in
+/sys/vax/vmparam.h).
+Each page of system page tables allows 8 megabytes of user virtual memory.
+.PP
+Because the file system block numbers are stored in
+page table \fIpg_blkno\fP
+entries, the maximum size of a file system is limited to
+2^24 1024 byte blocks. Thus no file system can be larger than 8 gigabytes.
+.PP
+The number of mountable file systems is set at 20 by the definition
+of NMOUNT in /sys/h/param.h.
+This should be sufficient; if not, the value can be increased up to 255.
+If you have many disks, it makes sense to make some of
+them single file systems, and the paging areas don't count in this total.
+.PP
+The limit to the number of files that a process may have open simultaneously
+is set to 64.
+This limit is set by the NOFILE definition in /sys/h/param.h.
+It may be increased arbitrarily, with the caveat that the user structure
+expands by 5 bytes for each file, and thus UPAGES (/sys/vax/machparam.h)
+must be increased accordingly.
+.PP
+The amount of physical memory is currently limited to 64 Mb
+by the size of the index fields in the core-map (/sys/h/cmap.h).
+The limit may be increased by following instructions in that file
+to enlarge those fields.
diff --git a/usr.sbin/config/SMM.doc/e.t b/usr.sbin/config/SMM.doc/e.t
new file mode 100644
index 0000000..0a9505b
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/e.t
@@ -0,0 +1,114 @@
+.\" 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.
+.\"
+.\" @(#)e.t 8.1 (Berkeley) 6/8/93
+.\"
+.\".ds RH "Network configuration options
+.bp
+.LG
+.B
+.ce
+APPENDIX E. NETWORK CONFIGURATION OPTIONS
+.sp
+.R
+.NL
+.PP
+The network support in the kernel is self-configuring
+according to the protocol support options (INET and NS) and the network
+hardware discovered during autoconfiguration.
+There are several changes that may be made to customize network behavior
+due to local restrictions.
+Within the Internet protocol routines, the following options
+set in the system configuration file are supported:
+.IP \fBGATEWAY\fP
+.br
+The machine is to be used as a gateway.
+This option currently makes only minor changes.
+First, the size of the network routing hash table is increased.
+Secondly, machines that have only a single hardware network interface
+will not forward IP packets; without this option, they will also refrain
+from sending any error indication to the source of unforwardable packets.
+Gateways with only a single interface are assumed to have missing
+or broken interfaces, and will return ICMP unreachable errors to hosts
+sending them packets to be forwarded.
+.IP \fBTCP_COMPAT_42\fP
+.br
+This option forces the system to limit its initial TCP sequence numbers
+to positive numbers.
+Without this option, 4.4BSD systems may have problems with TCP connections
+to 4.2BSD systems that connect but never transfer data.
+The problem is a bug in the 4.2BSD TCP.
+.IP \fBIPFORWARDING\fP
+.br
+Normally, 4.4BSD machines with multiple network interfaces
+will forward IP packets received that should be resent to another host.
+If the line ``options IPFORWARDING="0"'' is in the system configuration
+file, IP packet forwarding will be disabled.
+.IP \fBIPSENDREDIRECTS\fP
+.br
+When forwarding IP packets, 4.4BSD IP will note when a packet is forwarded
+using the same interface on which it arrived.
+When this is noted, if the source machine is on the directly-attached
+network, an ICMP redirect is sent to the source host.
+If the packet was forwarded using a route to a host or to a subnet,
+a host redirect is sent, otherwise a network redirect is sent.
+The generation of redirects may be inhibited with the configuration
+option ``options IPSENDREDIRECTS="0".''
+.br
+.IP \fBSUBNETSARELOCAL\fP
+TCP calculates a maximum segment size to use for each connection,
+and sends no datagrams larger than that size.
+This size will be no larger than that supported on the outgoing
+interface.
+Furthermore, if the destination is not on the local network,
+the size will be no larger than 576 bytes.
+For this test, other subnets of a directly-connected subnetted
+network are considered to be local unless the line
+``options SUBNETSARELOCAL="0"'' is used in the system configuration file.
+.LP
+The following options are supported by the Xerox NS protocols:
+.IP \fBNSIP\fP
+.br
+This option allows NS IDP datagrams to be encapsulated in Internet IP
+packets for transmission to a collaborating NSIP host.
+This may be used to pass IDP packets through IP-only link layer networks.
+See
+.IR nsip (4P)
+for details.
+.IP \fBTHREEWAYSHAKE\fP
+.br
+The NS Sequenced Packet Protocol does not require a three-way handshake
+before considering a connection to be in the established state.
+(A three-way handshake consists of a connection request, an acknowledgement
+of the request along with a symmetrical opening indication,
+and then an acknowledgement of the reciprocal opening packet.)
+This option forces a three-way handshake before data may be transmitted
+on Sequenced Packet sockets.
diff --git a/usr.sbin/config/SMM.doc/spell.ok b/usr.sbin/config/SMM.doc/spell.ok
new file mode 100644
index 0000000..50c4ef2
--- /dev/null
+++ b/usr.sbin/config/SMM.doc/spell.ok
@@ -0,0 +1,306 @@
+ACC
+ANSEL
+ARP
+Autoconfiguration
+BUFPAGES
+CANTWAIT
+CH
+COMPAT
+CSS
+Co
+Config
+Config''SMM:2
+DCLR
+DFLDSIZ
+DFLSSIZ
+DFUNNY
+DHAHA
+DMA
+Dev
+Dquot
+ECC
+EMULEX
+Emulex
+Ethernet
+FPNUMBER
+FUNNY,HAHA
+HAVEBDP
+ICMP
+IDP
+IE
+INET
+IP
+IPC
+IPFORWARDING
+IPL
+IPSENDREDIRECTS
+Info
+Karels
+LH
+Leffler
+MAKEDEV
+MAKEDEV.local
+MASSBUS
+MAXDSIZ
+MAXTSIZ
+Makefile
+Mb
+MicroVAX
+Mkopt
+Mkoption
+NBUF
+NEED16
+NEEDBDP
+NINODE
+NMOUNT
+NOFILE
+NPROC
+NS
+NSC
+NSIP
+NUP
+PST
+RCS
+RDY
+RH
+RK07
+RK611
+SCCS
+SITENAME
+SMM:2
+SUBNETSARELOCAL
+SYSPTSIZE
+TCP
+THREEWAYSHAKE
+Timezone
+UCBVAX
+UDP
+UNIBUS
+UPAGES
+UPCS2
+USRPTSIZE
+VAX
+VAX630
+VAX730
+VAX750
+VAX780
+VAX8600
+VAXWELL
+VAXen
+Vax
+Vaxwell
+acc0
+accrint
+accxint
+addr
+arg
+args
+assym.s
+autoconfiguration
+autoconfigure
+autoconfigured
+backpointer
+badaddr
+blkno
+br
+br5
+buf
+bufpages
+buses
+caddr
+callout
+catchall
+cmap.h
+cmd
+conf
+conf.c
+config
+csr
+ct.c
+ctlr
+cvec
+datagrams
+define''s
+dev
+devices.machine
+dgo
+dh.c
+dh0
+dh1
+dh2
+dhreg.h
+dhrint
+dhxint
+dinfo
+dk
+dk.h
+dm0
+dmintr
+dname
+dquot
+dst
+dumpdev
+dumplo
+dumpmagic
+dumpsize
+dz.c
+dz0
+dzrint
+dzxint
+ec0
+eccollide
+ecrint
+ecxint
+endif
+es
+files.machine
+filesystem
+foo
+foo.c
+genkernel
+gettimeofday
+gigabytes
+gprof
+hardwired
+hd
+hk
+hk0
+hkkernel
+howmany
+hp0
+hp0b
+hp1
+hp2
+hp3
+hpkernel
+ht0
+hz
+ident
+ifdef
+ifndef
+il0
+ilcint
+ilrint
+info
+intr
+ioconf.c
+kgmon
+linterrs
+loopback
+machdep.c
+machparam.h
+makefile
+makelinks
+makeoptions
+maxusers
+mba
+mba0
+mba1
+mbuf.h
+mcount.c
+memsize
+minfo
+mname
+moniker
+mspw
+nbuf
+ncallout
+nclist
+ndquot
+ndrive
+netimp
+netinet
+netns
+netstat
+nexi
+nexus
+nfile
+ninode
+nmbclusters
+nnn.ddd
+nproc
+nquota
+nsip
+ntext
+optionlist
+param.c
+param.h
+pathnames
+pg
+physaddr
+pty
+rc
+reg
+rk.c
+rk0
+rk1
+rkintr
+savecore
+sc
+sc0
+sc1
+scdriver
+setrlimit
+sizeof
+softc
+source.c
+subr
+swapxxx.c
+sysname
+te0
+te1
+timezone
+tm0
+tmintr
+tu0
+uba
+uba.c
+uba0
+ubago
+uballoc
+ubamem
+ubanum
+ubareg.h
+ubarelse
+ubavar.h
+ubglue.s
+ubinfo
+ud
+ui
+um
+up.c
+up0
+up1
+up2
+upaddr
+upattach
+upba
+upcs1
+upcs2
+updevice
+updgo
+updinfo
+updtab
+upintr
+upip
+upmaptype
+upminfo
+upprobe
+upslave
+upstd
+upkernel
+upwatch
+upwstart
+value,name2
+value2
+vax
+vaxif
+vaxmba
+vaxuba
+vmparam.h
+kernel
+wildcard
+wildcarded
+wildcarding
+xclu
+xxx
diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8
new file mode 100644
index 0000000..798bafc
--- /dev/null
+++ b/usr.sbin/config/config.8
@@ -0,0 +1,177 @@
+.\" 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.
+.\"
+.\" @(#)config.8 8.2 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.Dt CONFIG 8
+.Os BSD 4
+.Sh NAME
+.Nm config
+.Nd build system configuration files
+.Sh SYNOPSIS
+.Nm config
+.Op Fl gp
+.Ar SYSTEM_NAME
+.Sh DESCRIPTION
+.Pp
+This is the old version of the
+.Nm config
+program.
+It understands the old autoconfiguration scheme
+used on the HP300, i386, DECstation, and derivative platforms.
+The new version of config is used with the
+SPARC platform.
+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 system configuration files from the file
+.Ar SYSTEM_NAME
+which describes
+the system to configure.
+A second file
+tells
+.Nm config
+what files are needed to generate a system and
+can be augmented by configuration specific set of files
+that give alternate files for a specific machine.
+(see the
+.Sx FILES
+section below)
+.Pp
+Available option and operand:
+.Pp
+.Bl -tag -width SYSTEM_NAME
+.It Fl g
+If the
+.Fl g
+option is supplied,
+.Nm config
+will configure a system for debugging.
+.It Fl p
+If the
+.Fl p
+option is supplied,
+.Nm config
+will configure a system for profiling; for example,
+.Xr kgmon 8
+and
+.Xr gprof 1 .
+.It Ar SYSTEM_NAME
+specifies the name of the system configuration file
+containing device specifications, configuration options
+and other system parameters for one system configuration.
+.El
+.Pp
+.Nm Config
+should be run from the
+.Pa conf
+subdirectory of the system source (usually
+.Pa /sys/ARCH/conf ) .
+.Nm Config
+assumes the directory
+.Pa ../../compile/SYSTEM_NAME
+exists and places all output files there.
+The output of
+.Nm config
+consists of a number of files; for the
+.Tn i386 ,
+they are:
+.Pa ioconf.c ,
+a description
+of what I/O devices are attached to the system;
+.Pa vector.h ,
+definitions of
+macros related to counting interrupts;
+.Pa Makefile ,
+used by
+.Xr make 1
+in building the system;
+header files,
+definitions of
+the number of various devices that will be compiled into the system;
+swap configuration files,
+definitions for
+the disk areas to be used for swapping, the root file system,
+argument processing, and system dumps.
+.Pp
+After running
+.Nm config ,
+it is necessary 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 any other error messages are produced by
+.Nm config ,
+the problems in the configuration file should be corrected and
+.Nm config
+should be run again.
+Attempts to compile a system that had configuration errors
+are likely to fail.
+.Sh FILES
+.Bl -tag -width /sys/i386/conf/Makefile.i386 -compact
+.It Pa /sys/conf/files
+list of common files system is built from
+.It Pa /sys/i386/conf/Makefile.i386
+generic makefile for the
+.Tn i386
+.It Pa /sys/i386/conf/files.i386
+list of
+.Tn i386
+specific files
+.It Pa /sys/i386/conf/devices.i386
+name to major device mapping file for the
+.Tn i386
+.It Pa /sys/i386/conf/files. Ns Em ERNIE
+list of files specific to
+.Em ERNIE
+system
+.El
+.Sh SEE ALSO
+The SYNOPSIS portion of each device in section 4.
+.Rs
+.%T "Building 4.3 BSD UNIX System with Config"
+.Re
+.sp
+.Xr config.new 8
+.Sh BUGS
+The line numbers reported in error messages are usually off by one.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.1 .
diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h
new file mode 100644
index 0000000..012a249
--- /dev/null
+++ b/usr.sbin/config/config.h
@@ -0,0 +1,212 @@
+/*
+ * Copyright (c) 1980, 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.
+ *
+ * @(#)config.h 8.1 (Berkeley) 6/6/93
+ */
+
+/*
+ * Config.
+ */
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define NODEV ((dev_t)-1)
+
+struct file_list {
+ struct file_list *f_next;
+ char *f_fn; /* the name */
+ u_char f_type; /* see below */
+ u_char f_flags; /* see below */
+ char *f_special; /* special make rule if present */
+ char *f_needs;
+ /*
+ * Random values:
+ * swap space parameters for swap areas
+ * root device, etc. for system specifications
+ */
+ union {
+ struct { /* when swap specification */
+ dev_t fuw_swapdev;
+ int fuw_swapsize;
+ int fuw_swapflag;
+ } fuw;
+ struct { /* when system specification */
+ dev_t fus_rootdev;
+ dev_t fus_dumpdev;
+ } fus;
+ struct { /* when component dev specification */
+ dev_t fup_compdev;
+ int fup_compinfo;
+ } fup;
+ } fun;
+#define f_swapdev fun.fuw.fuw_swapdev
+#define f_swapsize fun.fuw.fuw_swapsize
+#define f_swapflag fun.fuw.fuw_swapflag
+#define f_rootdev fun.fus.fus_rootdev
+#define f_dumpdev fun.fus.fus_dumpdev
+#define f_compdev fun.fup.fup_compdev
+#define f_compinfo fun.fup.fup_compinfo
+};
+
+/*
+ * Types.
+ */
+#define DRIVER 1
+#define NORMAL 2
+#define INVISIBLE 3
+#define PROFILING 4
+#define SYSTEMSPEC 5
+#define SWAPSPEC 6
+#define COMPDEVICE 7
+#define COMPSPEC 8
+
+/*
+ * Attributes (flags).
+ */
+#define CONFIGDEP 1
+
+struct idlst {
+ char *id;
+ struct idlst *id_next;
+};
+
+struct device {
+ int d_type; /* CONTROLLER, DEVICE, bus adaptor */
+ struct device *d_conn; /* what it is connected to */
+ char *d_name; /* name of device (e.g. rk11) */
+ struct idlst *d_vec; /* interrupt vectors */
+ int d_pri; /* interrupt priority */
+ int d_addr; /* address of csr */
+ int d_unit; /* unit number */
+ int d_drive; /* drive number */
+ int d_slave; /* slave number */
+#define QUES -1 /* -1 means '?' */
+#define UNKNOWN -2 /* -2 means not set yet */
+ int d_dk; /* if init 1 set to number for iostat */
+ int d_flags; /* flags for device init */
+ char *d_port; /* io port base manifest constant */
+ int d_portn; /* io port base (if number not manifest) */
+ char *d_mask; /* interrupt mask */
+ int d_maddr; /* io memory base */
+ int d_msize; /* io memory size */
+ int d_drq; /* DMA request */
+ int d_irq; /* interrupt request */
+ struct device *d_next; /* Next one in list */
+};
+#define TO_NEXUS (struct device *)-1
+#define TO_VBA (struct device *)-2
+
+struct config {
+ char *c_dev;
+ char *s_sysname;
+};
+
+/*
+ * Config has a global notion of which machine type is
+ * being used. It uses the name of the machine in choosing
+ * files and directories. Thus if the name of the machine is ``vax'',
+ * it will build from ``Makefile.vax'' and use ``../vax/inline''
+ * in the makerules, etc.
+ */
+int machine;
+char *machinename;
+#define MACHINE_VAX 1
+#define MACHINE_TAHOE 2
+#define MACHINE_HP300 3
+#define MACHINE_I386 4
+#define MACHINE_MIPS 5
+#define MACHINE_PMAX 6
+#define MACHINE_LUNA68K 7
+#define MACHINE_NEWS3400 8
+
+/*
+ * For each machine, a set of CPU's may be specified as supported.
+ * These and the options (below) are put in the C flags in the makefile.
+ */
+struct cputype {
+ char *cpu_name;
+ struct cputype *cpu_next;
+} *cputype;
+
+/*
+ * A set of options may also be specified which are like CPU types,
+ * but which may also specify values for the options.
+ * A separate set of options may be defined for make-style options.
+ */
+struct opt {
+ char *op_name;
+ char *op_value;
+ struct opt *op_next;
+} *opt, *mkopt;
+
+char *ident;
+char *ns();
+char *tc();
+char *qu();
+char *get_word();
+char *get_quoted_word();
+char *path();
+char *raise();
+
+int do_trace;
+
+#if MACHINE_VAX
+int seen_mba, seen_uba;
+#endif
+#if MACHINE_TAHOE
+int seen_vba;
+#endif
+#if MACHINE_I386
+int seen_isa;
+#endif
+int seen_cd;
+
+struct device *connect();
+struct device *dtab;
+dev_t nametodev();
+char *devtoname();
+
+char errbuf[80];
+int yyline;
+
+struct file_list *ftab, *conf_list, **confp, *comp_list, **compp;
+
+int zone, hadtz;
+int dst;
+int profiling;
+int debugging;
+
+int maxusers;
+u_int loadaddress;
+
+#define eq(a,b) (!strcmp(a,b))
diff --git a/usr.sbin/config/config.y b/usr.sbin/config/config.y
new file mode 100644
index 0000000..9a041d0
--- /dev/null
+++ b/usr.sbin/config/config.y
@@ -0,0 +1,1115 @@
+%union {
+ char *str;
+ int val;
+ struct file_list *file;
+ struct idlst *lst;
+}
+
+%token AND
+%token ANY
+%token ARGS
+%token AT
+%token BIO
+%token COMMA
+%token CONFIG
+%token CONTROLLER
+%token CPU
+%token CSR
+%token DEVICE
+%token DISK
+%token DRIVE
+%token DRQ
+%token DST
+%token DUMPS
+%token EQUALS
+%token FLAGS
+%token HZ
+%token IDENT
+%token INTERLEAVE
+%token IOMEM
+%token IOSIZ
+%token IRQ
+%token MACHINE
+%token MAJOR
+%token MASTER
+%token MAXUSERS
+%token MINOR
+%token MINUS
+%token NET
+%token NEXUS
+%token ON
+%token OPTIONS
+%token MAKEOPTIONS
+%token PORT
+%token PRIORITY
+%token PSEUDO_DEVICE
+%token ROOT
+%token SEMICOLON
+%token SEQUENTIAL
+%token SIZE
+%token SLAVE
+%token SWAP
+%token TIMEZONE
+%token TTY
+%token TRACE
+%token VECTOR
+
+%token <str> ID
+%token <val> NUMBER
+%token <val> FPNUMBER
+
+%type <str> Save_id
+%type <str> Opt_value
+%type <str> Dev
+%type <lst> Id_list
+%type <val> optional_size
+%type <val> optional_sflag
+%type <str> device_name
+%type <val> major_minor
+%type <val> arg_device_spec
+%type <val> root_device_spec
+%type <val> dump_device_spec
+%type <file> swap_device_spec
+%type <file> comp_device_spec
+
+%{
+
+/*
+ * 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.
+ *
+ * @(#)config.y 8.1 (Berkeley) 6/6/93
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include <stdio.h>
+
+struct device cur;
+struct device *curp = 0;
+char *temp_id;
+char *val_id;
+
+%}
+%%
+Configuration:
+ Many_specs
+ = { verifysystemspecs(); }
+ ;
+
+Many_specs:
+ Many_specs Spec
+ |
+ /* lambda */
+ ;
+
+Spec:
+ Device_spec SEMICOLON
+ = { newdev(&cur); } |
+ Config_spec SEMICOLON
+ |
+ TRACE SEMICOLON
+ = { do_trace = !do_trace; } |
+ SEMICOLON
+ |
+ error SEMICOLON
+ ;
+
+Config_spec:
+ MACHINE Save_id
+ = {
+ if (!strcmp($2, "vax")) {
+ machine = MACHINE_VAX;
+ machinename = "vax";
+ } else if (!strcmp($2, "tahoe")) {
+ machine = MACHINE_TAHOE;
+ machinename = "tahoe";
+ } else if (!strcmp($2, "hp300")) {
+ machine = MACHINE_HP300;
+ machinename = "hp300";
+ } else if (!strcmp($2, "i386")) {
+ machine = MACHINE_I386;
+ machinename = "i386";
+ } else if (!strcmp($2, "mips")) {
+ machine = MACHINE_MIPS;
+ machinename = "mips";
+ } else if (!strcmp($2, "pmax")) {
+ machine = MACHINE_PMAX;
+ machinename = "pmax";
+ } else if (!strcmp($2, "luna68k")) {
+ machine = MACHINE_LUNA68K;
+ machinename = "luna68k";
+ } else if (!strcmp($2, "news3400")) {
+ machine = MACHINE_NEWS3400;
+ machinename = "news3400";
+ } else
+ yyerror("Unknown machine type");
+ } |
+ CPU Save_id
+ = {
+ struct cputype *cp =
+ (struct cputype *)malloc(sizeof (struct cputype));
+ cp->cpu_name = ns($2);
+ cp->cpu_next = cputype;
+ cputype = cp;
+ free(temp_id);
+ } |
+ OPTIONS Opt_list
+ |
+ MAKEOPTIONS Mkopt_list
+ |
+ IDENT ID
+ = { ident = ns($2); } |
+ System_spec
+ |
+ HZ NUMBER
+ = { yyerror("HZ specification obsolete; delete"); } |
+ TIMEZONE NUMBER
+ = { zone = 60 * $2; check_tz(); } |
+ TIMEZONE NUMBER DST NUMBER
+ = { zone = 60 * $2; dst = $4; check_tz(); } |
+ TIMEZONE NUMBER DST
+ = { zone = 60 * $2; dst = 1; check_tz(); } |
+ TIMEZONE FPNUMBER
+ = { zone = $2; check_tz(); } |
+ TIMEZONE FPNUMBER DST NUMBER
+ = { zone = $2; dst = $4; check_tz(); } |
+ TIMEZONE FPNUMBER DST
+ = { zone = $2; dst = 1; check_tz(); } |
+ TIMEZONE MINUS NUMBER
+ = { zone = -60 * $3; check_tz(); } |
+ TIMEZONE MINUS NUMBER DST NUMBER
+ = { zone = -60 * $3; dst = $5; check_tz(); } |
+ TIMEZONE MINUS NUMBER DST
+ = { zone = -60 * $3; dst = 1; check_tz(); } |
+ TIMEZONE MINUS FPNUMBER
+ = { zone = -$3; check_tz(); } |
+ TIMEZONE MINUS FPNUMBER DST NUMBER
+ = { zone = -$3; dst = $5; check_tz(); } |
+ TIMEZONE MINUS FPNUMBER DST
+ = { zone = -$3; dst = 1; check_tz(); } |
+ MAXUSERS NUMBER
+ = { maxusers = $2; };
+
+System_spec:
+ System_id System_parameter_list
+ = { checksystemspec(*confp); }
+ ;
+
+System_id:
+ CONFIG Save_id
+ = { mkconf($2); }
+ ;
+
+System_parameter_list:
+ System_parameter_list System_parameter
+ | System_parameter
+ ;
+
+System_parameter:
+ addr_spec
+ | swap_spec
+ | root_spec
+ | dump_spec
+ | arg_spec
+ ;
+
+addr_spec:
+ AT NUMBER
+ = { loadaddress = $2; };
+ ;
+
+swap_spec:
+ SWAP optional_on swap_device_list
+ ;
+
+swap_device_list:
+ swap_device_list AND swap_device
+ | swap_device
+ ;
+
+swap_device:
+ swap_device_spec optional_size optional_sflag
+ = { mkswap(*confp, $1, $2, $3); }
+ ;
+
+swap_device_spec:
+ device_name
+ = {
+ struct file_list *fl = newflist(SWAPSPEC);
+
+ if (eq($1, "generic"))
+ fl->f_fn = $1;
+ else {
+ fl->f_swapdev = nametodev($1, 0, 'b');
+ fl->f_fn = devtoname(fl->f_swapdev);
+ }
+ $$ = fl;
+ }
+ | major_minor
+ = {
+ struct file_list *fl = newflist(SWAPSPEC);
+
+ fl->f_swapdev = $1;
+ fl->f_fn = devtoname($1);
+ $$ = fl;
+ }
+ ;
+
+root_spec:
+ ROOT optional_on root_device_spec
+ = {
+ struct file_list *fl = *confp;
+
+ if (fl && fl->f_rootdev != NODEV)
+ yyerror("extraneous root device specification");
+ else
+ fl->f_rootdev = $3;
+ }
+ ;
+
+root_device_spec:
+ device_name
+ = { $$ = nametodev($1, 0, 'a'); }
+ | major_minor
+ ;
+
+dump_spec:
+ DUMPS optional_on dump_device_spec
+ = {
+ struct file_list *fl = *confp;
+
+ if (fl && fl->f_dumpdev != NODEV)
+ yyerror("extraneous dump device specification");
+ else
+ fl->f_dumpdev = $3;
+ }
+
+ ;
+
+dump_device_spec:
+ device_name
+ = { $$ = nametodev($1, 0, 'b'); }
+ | major_minor
+ ;
+
+arg_spec:
+ ARGS optional_on arg_device_spec
+ = { yyerror("arg device specification obsolete, ignored"); }
+ ;
+
+arg_device_spec:
+ device_name
+ = { $$ = nametodev($1, 0, 'b'); }
+ | major_minor
+ ;
+
+major_minor:
+ MAJOR NUMBER MINOR NUMBER
+ = { $$ = makedev($2, $4); }
+ ;
+
+optional_on:
+ ON
+ | /* empty */
+ ;
+
+optional_size:
+ SIZE NUMBER
+ = { $$ = $2; }
+ | /* empty */
+ = { $$ = 0; }
+ ;
+
+optional_sflag:
+ SEQUENTIAL
+ = { $$ = 2; }
+ | /* empty */
+ = { $$ = 0; }
+ ;
+
+device_name:
+ Save_id
+ = { $$ = $1; }
+ | Save_id NUMBER
+ = {
+ char buf[80];
+
+ (void) sprintf(buf, "%s%d", $1, $2);
+ $$ = ns(buf); free($1);
+ }
+ | Save_id NUMBER ID
+ = {
+ char buf[80];
+
+ (void) sprintf(buf, "%s%d%s", $1, $2, $3);
+ $$ = ns(buf); free($1);
+ }
+ ;
+
+Opt_list:
+ Opt_list COMMA Option
+ |
+ Option
+ ;
+
+Option:
+ Save_id
+ = {
+ struct opt *op = (struct opt *)malloc(sizeof (struct opt));
+ op->op_name = ns($1);
+ op->op_next = opt;
+ op->op_value = 0;
+ opt = op;
+ free(temp_id);
+ } |
+ Save_id EQUALS Opt_value
+ = {
+ struct opt *op = (struct opt *)malloc(sizeof (struct opt));
+ op->op_name = ns($1);
+ op->op_next = opt;
+ op->op_value = ns($3);
+ opt = op;
+ free(temp_id);
+ free(val_id);
+ } ;
+
+Opt_value:
+ ID
+ = { $$ = val_id = ns($1); } |
+ NUMBER
+ = {
+ char nb[16];
+ (void) sprintf(nb, "%d", $1);
+ $$ = val_id = ns(nb);
+ } ;
+
+
+Save_id:
+ ID
+ = { $$ = temp_id = ns($1); }
+ ;
+
+Mkopt_list:
+ Mkopt_list COMMA Mkoption
+ |
+ Mkoption
+ ;
+
+Mkoption:
+ Save_id EQUALS Opt_value
+ = {
+ struct opt *op = (struct opt *)malloc(sizeof (struct opt));
+ op->op_name = ns($1);
+ op->op_next = mkopt;
+ op->op_value = ns($3);
+ mkopt = op;
+ free(temp_id);
+ free(val_id);
+ } ;
+
+Dev:
+ ID
+ = { $$ = ns($1); }
+ ;
+
+Device_spec:
+ DEVICE Dev_name Dev_info Int_spec
+ = { cur.d_type = DEVICE; } |
+ MASTER Dev_name Dev_info Int_spec
+ = { cur.d_type = MASTER; } |
+ DISK Dev_name Dev_info Int_spec
+ = { cur.d_dk = 1; cur.d_type = DEVICE; } |
+ CONTROLLER Dev_name Dev_info Int_spec
+ = { cur.d_type = CONTROLLER; } |
+ PSEUDO_DEVICE Init_dev Dev
+ = {
+ cur.d_name = $3;
+ cur.d_type = PSEUDO_DEVICE;
+ } |
+ PSEUDO_DEVICE Init_dev Dev NUMBER
+ = {
+ cur.d_name = $3;
+ cur.d_type = PSEUDO_DEVICE;
+ cur.d_slave = $4;
+ } |
+ PSEUDO_DEVICE Dev_name Cdev_init Cdev_info
+ = {
+ if (!eq(cur.d_name, "cd"))
+ yyerror("improper spec for pseudo-device");
+ seen_cd = 1;
+ cur.d_type = DEVICE;
+ verifycomp(*compp);
+ };
+
+Cdev_init:
+ /* lambda */
+ = { mkcomp(&cur); };
+
+Cdev_info:
+ optional_on comp_device_list comp_option_list
+ ;
+
+comp_device_list:
+ comp_device_list AND comp_device
+ | comp_device
+ ;
+
+comp_device:
+ comp_device_spec
+ = { addcomp(*compp, $1); }
+ ;
+
+comp_device_spec:
+ device_name
+ = {
+ struct file_list *fl = newflist(COMPSPEC);
+
+ fl->f_compdev = nametodev($1, 0, 'c');
+ fl->f_fn = devtoname(fl->f_compdev);
+ $$ = fl;
+ }
+ | major_minor
+ = {
+ struct file_list *fl = newflist(COMPSPEC);
+
+ fl->f_compdev = $1;
+ fl->f_fn = devtoname($1);
+ $$ = fl;
+ }
+ ;
+
+comp_option_list:
+ comp_option_list comp_option
+ |
+ /* lambda */
+ ;
+
+comp_option:
+ INTERLEAVE NUMBER
+ = { cur.d_pri = $2; } |
+ FLAGS NUMBER
+ = { cur.d_flags = $2; };
+
+Dev_name:
+ Init_dev Dev NUMBER
+ = {
+ cur.d_name = $2;
+ if (eq($2, "mba"))
+ seen_mba = 1;
+ else if (eq($2, "uba"))
+ seen_uba = 1;
+ else if (eq($2, "vba"))
+ seen_vba = 1;
+ else if (eq($2, "isa"))
+ seen_isa = 1;
+ cur.d_unit = $3;
+ };
+
+Init_dev:
+ /* lambda */
+ = { init_dev(&cur); };
+
+Dev_info:
+ Con_info Info_list
+ |
+ /* lambda */
+ ;
+
+Con_info:
+ AT Dev NUMBER
+ = {
+ if (eq(cur.d_name, "mba") || eq(cur.d_name, "uba")) {
+ (void) sprintf(errbuf,
+ "%s must be connected to a nexus", cur.d_name);
+ yyerror(errbuf);
+ }
+ cur.d_conn = connect($2, $3);
+ } |
+ AT NEXUS NUMBER
+ = { check_nexus(&cur, $3); cur.d_conn = TO_NEXUS; };
+
+Info_list:
+ Info_list Info
+ |
+ /* lambda */
+ ;
+
+Info:
+ CSR NUMBER
+ = { cur.d_addr = $2; } |
+ DRIVE NUMBER
+ = { cur.d_drive = $2; } |
+ SLAVE NUMBER
+ = {
+ if (cur.d_conn != 0 && cur.d_conn != TO_NEXUS &&
+ cur.d_conn->d_type == MASTER)
+ cur.d_slave = $2;
+ else
+ yyerror("can't specify slave--not to master");
+ } |
+ IRQ NUMBER
+ = { cur.d_irq = $2; } |
+ DRQ NUMBER
+ = { cur.d_drq = $2; } |
+ IOMEM NUMBER
+ = { cur.d_maddr = $2; } |
+ IOSIZ NUMBER
+ = { cur.d_msize = $2; } |
+ PORT device_name
+ = { cur.d_port = ns($2); } |
+ PORT NUMBER
+ = { cur.d_portn = $2; } |
+ TTY
+ = { cur.d_mask = "tty"; } |
+ BIO
+ = { cur.d_mask = "bio"; } |
+ NET
+ = { cur.d_mask = "net"; } |
+ FLAGS NUMBER
+ = { cur.d_flags = $2; };
+
+Int_spec:
+ VECTOR Id_list
+ = { cur.d_vec = $2; } |
+ PRIORITY NUMBER
+ = { cur.d_pri = $2; } |
+ /* lambda */
+ ;
+
+Id_list:
+ Save_id
+ = {
+ struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
+ a->id = $1; a->id_next = 0; $$ = a;
+ } |
+ Save_id Id_list =
+ {
+ struct idlst *a = (struct idlst *)malloc(sizeof(struct idlst));
+ a->id = $1; a->id_next = $2; $$ = a;
+ };
+
+%%
+
+yyerror(s)
+ char *s;
+{
+
+ fprintf(stderr, "config: line %d: %s\n", yyline + 1, s);
+}
+
+/*
+ * return the passed string in a new space
+ */
+char *
+ns(str)
+ register char *str;
+{
+ register char *cp;
+
+ cp = malloc((unsigned)(strlen(str)+1));
+ (void) strcpy(cp, str);
+ return (cp);
+}
+
+/*
+ * add a device to the list of devices
+ */
+newdev(dp)
+ register struct device *dp;
+{
+ register struct device *np;
+
+ np = (struct device *) malloc(sizeof *np);
+ *np = *dp;
+ np->d_next = 0;
+ if (curp == 0)
+ dtab = np;
+ else
+ curp->d_next = np;
+ curp = np;
+}
+
+/*
+ * note that a configuration should be made
+ */
+mkconf(sysname)
+ char *sysname;
+{
+ register struct file_list *fl, **flp;
+
+ fl = (struct file_list *) malloc(sizeof *fl);
+ fl->f_type = SYSTEMSPEC;
+ fl->f_needs = sysname;
+ fl->f_rootdev = NODEV;
+ fl->f_dumpdev = NODEV;
+ fl->f_fn = 0;
+ fl->f_next = 0;
+ for (flp = confp; *flp; flp = &(*flp)->f_next)
+ ;
+ *flp = fl;
+ confp = flp;
+}
+
+struct file_list *
+newflist(ftype)
+ u_char ftype;
+{
+ struct file_list *fl = (struct file_list *)malloc(sizeof (*fl));
+
+ fl->f_type = ftype;
+ fl->f_next = 0;
+ fl->f_swapdev = NODEV;
+ fl->f_swapsize = 0;
+ fl->f_needs = 0;
+ fl->f_fn = 0;
+ return (fl);
+}
+
+/*
+ * Add a swap device to the system's configuration
+ */
+mkswap(system, fl, size, flag)
+ struct file_list *system, *fl;
+ int size, flag;
+{
+ register struct file_list **flp;
+ char name[80];
+
+ if (system == 0 || system->f_type != SYSTEMSPEC) {
+ yyerror("\"swap\" spec precedes \"config\" specification");
+ return;
+ }
+ if (size < 0) {
+ yyerror("illegal swap partition size");
+ return;
+ }
+ /*
+ * Append swap description to the end of the list.
+ */
+ flp = &system->f_next;
+ for (; *flp && (*flp)->f_type == SWAPSPEC; flp = &(*flp)->f_next)
+ ;
+ fl->f_next = *flp;
+ *flp = fl;
+ fl->f_swapsize = size;
+ fl->f_swapflag = flag;
+ /*
+ * If first swap device for this system,
+ * set up f_fn field to insure swap
+ * files are created with unique names.
+ */
+ if (system->f_fn)
+ return;
+ if (eq(fl->f_fn, "generic"))
+ system->f_fn = ns(fl->f_fn);
+ else
+ system->f_fn = ns(system->f_needs);
+}
+
+mkcomp(dp)
+ register struct device *dp;
+{
+ register struct file_list *fl, **flp;
+ char buf[80];
+
+ fl = (struct file_list *) malloc(sizeof *fl);
+ fl->f_type = COMPDEVICE;
+ fl->f_compinfo = dp->d_unit;
+ fl->f_fn = ns(dp->d_name);
+ (void) sprintf(buf, "%s%d", dp->d_name, dp->d_unit);
+ fl->f_needs = ns(buf);
+ fl->f_next = 0;
+ for (flp = compp; *flp; flp = &(*flp)->f_next)
+ ;
+ *flp = fl;
+ compp = flp;
+}
+
+addcomp(compdev, fl)
+ struct file_list *compdev, *fl;
+{
+ register struct file_list **flp;
+ char name[80];
+
+ if (compdev == 0 || compdev->f_type != COMPDEVICE) {
+ yyerror("component spec precedes device specification");
+ return;
+ }
+ /*
+ * Append description to the end of the list.
+ */
+ flp = &compdev->f_next;
+ for (; *flp && (*flp)->f_type == COMPSPEC; flp = &(*flp)->f_next)
+ ;
+ fl->f_next = *flp;
+ *flp = fl;
+}
+
+/*
+ * find the pointer to connect to the given device and number.
+ * returns 0 if no such device and prints an error message
+ */
+struct device *
+connect(dev, num)
+ register char *dev;
+ register int num;
+{
+ register struct device *dp;
+ struct device *huhcon();
+
+ if (num == QUES)
+ return (huhcon(dev));
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if ((num != dp->d_unit) || !eq(dev, dp->d_name))
+ continue;
+ if (dp->d_type != CONTROLLER && dp->d_type != MASTER) {
+ (void) sprintf(errbuf,
+ "%s connected to non-controller", dev);
+ yyerror(errbuf);
+ return (0);
+ }
+ return (dp);
+ }
+ (void) sprintf(errbuf, "%s %d not defined", dev, num);
+ yyerror(errbuf);
+ return (0);
+}
+
+/*
+ * connect to an unspecific thing
+ */
+struct device *
+huhcon(dev)
+ register char *dev;
+{
+ register struct device *dp, *dcp;
+ struct device rdev;
+ int oldtype;
+
+ /*
+ * First make certain that there are some of these to wildcard on
+ */
+ for (dp = dtab; dp != 0; dp = dp->d_next)
+ if (eq(dp->d_name, dev))
+ break;
+ if (dp == 0) {
+ (void) sprintf(errbuf, "no %s's to wildcard", dev);
+ yyerror(errbuf);
+ return (0);
+ }
+ oldtype = dp->d_type;
+ dcp = dp->d_conn;
+ /*
+ * Now see if there is already a wildcard entry for this device
+ * (e.g. Search for a "uba ?")
+ */
+ for (; dp != 0; dp = dp->d_next)
+ if (eq(dev, dp->d_name) && dp->d_unit == -1)
+ break;
+ /*
+ * If there isn't, make one because everything needs to be connected
+ * to something.
+ */
+ if (dp == 0) {
+ dp = &rdev;
+ init_dev(dp);
+ dp->d_unit = QUES;
+ dp->d_name = ns(dev);
+ dp->d_type = oldtype;
+ newdev(dp);
+ dp = curp;
+ /*
+ * Connect it to the same thing that other similar things are
+ * connected to, but make sure it is a wildcard unit
+ * (e.g. up connected to sc ?, here we make connect sc? to a
+ * uba?). If other things like this are on the NEXUS or
+ * if they aren't connected to anything, then make the same
+ * connection, else call ourself to connect to another
+ * unspecific device.
+ */
+ if (dcp == TO_NEXUS || dcp == 0)
+ dp->d_conn = dcp;
+ else
+ dp->d_conn = connect(dcp->d_name, QUES);
+ }
+ return (dp);
+}
+
+init_dev(dp)
+ register struct device *dp;
+{
+
+ dp->d_name = "OHNO!!!";
+ dp->d_type = DEVICE;
+ dp->d_conn = 0;
+ dp->d_vec = 0;
+ dp->d_addr = dp->d_flags = dp->d_dk = 0;
+ dp->d_pri = -1;
+ dp->d_slave = dp->d_drive = dp->d_unit = UNKNOWN;
+ dp->d_port = (char *)0;
+ dp->d_portn = 0;
+ dp->d_irq = -1;
+ dp->d_drq = -1;
+ dp->d_maddr = 0;
+ dp->d_msize = 0;
+ dp->d_mask = "null";
+}
+
+/*
+ * make certain that this is a reasonable type of thing to connect to a nexus
+ */
+check_nexus(dev, num)
+ register struct device *dev;
+ int num;
+{
+
+ switch (machine) {
+
+ case MACHINE_VAX:
+ if (!eq(dev->d_name, "uba") && !eq(dev->d_name, "mba") &&
+ !eq(dev->d_name, "bi"))
+ yyerror("only uba's, mba's, and bi's should be connected to the nexus");
+ if (num != QUES)
+ yyerror("can't give specific nexus numbers");
+ break;
+
+ case MACHINE_TAHOE:
+ if (!eq(dev->d_name, "vba"))
+ yyerror("only vba's should be connected to the nexus");
+ break;
+
+ case MACHINE_HP300:
+ case MACHINE_LUNA68K:
+ if (num != QUES)
+ dev->d_addr = num;
+ break;
+
+ case MACHINE_I386:
+ if (!eq(dev->d_name, "isa"))
+ yyerror("only isa's should be connected to the nexus");
+ break;
+
+ case MACHINE_NEWS3400:
+ if (!eq(dev->d_name, "iop") && !eq(dev->d_name, "hb") &&
+ !eq(dev->d_name, "vme"))
+ yyerror("only iop's, hb's and vme's should be connected to the nexus");
+ break;
+ }
+}
+
+/*
+ * Check the timezone to make certain it is sensible
+ */
+
+check_tz()
+{
+ if (zone != 0 || dst != 0)
+ yyerror("timezone specification is no longer permitted");
+ else
+ hadtz = 1;
+}
+
+/*
+ * Check system specification and apply defaulting
+ * rules on root, argument, dump, and swap devices.
+ */
+checksystemspec(fl)
+ register struct file_list *fl;
+{
+ char buf[BUFSIZ];
+ register struct file_list *swap;
+ int generic;
+
+ if (fl == 0 || fl->f_type != SYSTEMSPEC) {
+ yyerror("internal error, bad system specification");
+ exit(1);
+ }
+ swap = fl->f_next;
+ generic = swap && swap->f_type == SWAPSPEC && eq(swap->f_fn, "generic");
+ if (fl->f_rootdev == NODEV && !generic) {
+ yyerror("no root device specified");
+ exit(1);
+ }
+ /*
+ * Default swap area to be in 'b' partition of root's
+ * device. If root specified to be other than on 'a'
+ * partition, give warning, something probably amiss.
+ */
+ if (swap == 0 || swap->f_type != SWAPSPEC) {
+ dev_t dev;
+
+ swap = newflist(SWAPSPEC);
+ dev = fl->f_rootdev;
+ if (minor(dev) & 07) {
+ (void) sprintf(buf,
+"Warning, swap defaulted to 'b' partition with root on '%c' partition",
+ (minor(dev) & 07) + 'a');
+ yyerror(buf);
+ }
+ swap->f_swapdev =
+ makedev(major(dev), (minor(dev) &~ 07) | ('b' - 'a'));
+ swap->f_fn = devtoname(swap->f_swapdev);
+ mkswap(fl, swap, 0);
+ }
+ /*
+ * Make sure a generic swap isn't specified, along with
+ * other stuff (user must really be confused).
+ */
+ if (generic) {
+ if (fl->f_rootdev != NODEV)
+ yyerror("root device specified with generic swap");
+ if (fl->f_dumpdev != NODEV)
+ yyerror("dump device specified with generic swap");
+ return;
+ }
+ /*
+ * Default dump device and warn if place is not a
+ * swap area.
+ */
+ if (fl->f_dumpdev == NODEV)
+ fl->f_dumpdev = swap->f_swapdev;
+ if (fl->f_dumpdev != swap->f_swapdev) {
+ struct file_list *p = swap->f_next;
+
+ for (; p && p->f_type == SWAPSPEC; p = p->f_next)
+ if (fl->f_dumpdev == p->f_swapdev)
+ return;
+ (void) sprintf(buf,
+ "Warning: dump device is not a swap partition");
+ yyerror(buf);
+ }
+}
+
+/*
+ * Verify all devices specified in the system specification
+ * are present in the device specifications.
+ */
+verifysystemspecs()
+{
+ register struct file_list *fl;
+ dev_t checked[50], *verifyswap();
+ register dev_t *pchecked = checked;
+
+ for (fl = conf_list; fl; fl = fl->f_next) {
+ if (fl->f_type != SYSTEMSPEC)
+ continue;
+ if (!finddev(fl->f_rootdev))
+ deverror(fl->f_needs, "root");
+ *pchecked++ = fl->f_rootdev;
+ pchecked = verifyswap(fl->f_next, checked, pchecked);
+#define samedev(dev1, dev2) \
+ ((minor(dev1) &~ 07) != (minor(dev2) &~ 07))
+ if (!alreadychecked(fl->f_dumpdev, checked, pchecked)) {
+ if (!finddev(fl->f_dumpdev))
+ deverror(fl->f_needs, "dump");
+ *pchecked++ = fl->f_dumpdev;
+ }
+ }
+}
+
+/*
+ * Do as above, but for swap devices.
+ */
+dev_t *
+verifyswap(fl, checked, pchecked)
+ register struct file_list *fl;
+ dev_t checked[];
+ register dev_t *pchecked;
+{
+
+ for (;fl && fl->f_type == SWAPSPEC; fl = fl->f_next) {
+ if (eq(fl->f_fn, "generic"))
+ continue;
+ if (alreadychecked(fl->f_swapdev, checked, pchecked))
+ continue;
+ if (!finddev(fl->f_swapdev))
+ fprintf(stderr,
+ "config: swap device %s not configured", fl->f_fn);
+ *pchecked++ = fl->f_swapdev;
+ }
+ return (pchecked);
+}
+
+/*
+ * Verify that components of a compound device have themselves been config'ed
+ */
+verifycomp(fl)
+ register struct file_list *fl;
+{
+ char *dname = fl->f_needs;
+
+ for (fl = fl->f_next; fl; fl = fl->f_next) {
+ if (fl->f_type != COMPSPEC || finddev(fl->f_compdev))
+ continue;
+ fprintf(stderr,
+ "config: %s: component device %s not configured\n",
+ dname, fl->f_needs);
+ }
+}
+
+/*
+ * Has a device already been checked
+ * for it's existence in the configuration?
+ */
+alreadychecked(dev, list, last)
+ dev_t dev, list[];
+ register dev_t *last;
+{
+ register dev_t *p;
+
+ for (p = list; p < last; p++)
+ if (samedev(*p, dev))
+ return (1);
+ return (0);
+}
+
+deverror(systemname, devtype)
+ char *systemname, *devtype;
+{
+
+ fprintf(stderr, "config: %s: %s device not configured\n",
+ systemname, devtype);
+}
+
+/*
+ * Look for the device in the list of
+ * configured hardware devices. Must
+ * take into account stuff wildcarded.
+ */
+/*ARGSUSED*/
+finddev(dev)
+ dev_t dev;
+{
+
+ /* punt on this right now */
+ return (1);
+}
diff --git a/usr.sbin/config/lang.l b/usr.sbin/config/lang.l
new file mode 100644
index 0000000..535ffcd
--- /dev/null
+++ b/usr.sbin/config/lang.l
@@ -0,0 +1,215 @@
+%{
+/*-
+ * Copyright (c) 1980, 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.
+ *
+ * @(#)lang.l 8.1 (Berkeley) 6/6/93
+ */
+
+#include <ctype.h>
+#include "y.tab.h"
+#include "config.h"
+
+#define tprintf if (do_trace) printf
+
+/*
+ * Key word table
+ */
+
+struct kt {
+ char *kt_name;
+ int kt_val;
+} key_words[] = {
+ { "and", AND },
+ { "args", ARGS },
+ { "at", AT },
+#if MACHINE_I386
+ { "bio", BIO },
+#endif MACHINE_I386
+ { "config", CONFIG },
+ { "controller", CONTROLLER },
+ { "cpu", CPU },
+ { "csr", CSR },
+ { "device", DEVICE },
+ { "disk", DISK },
+ { "drive", DRIVE },
+#if MACHINE_I386
+ { "drq", DRQ },
+#endif MACHINE_I386
+ { "dst", DST },
+ { "dumps", DUMPS },
+ { "flags", FLAGS },
+ { "hz", HZ },
+ { "ident", IDENT },
+ { "interleave", INTERLEAVE },
+#if MACHINE_I386
+ { "iomem", IOMEM },
+ { "iosiz", IOSIZ },
+ { "irq", IRQ },
+#endif MACHINE_I386
+ { "machine", MACHINE },
+ { "major", MAJOR },
+ { "makeoptions", MAKEOPTIONS },
+ { "master", MASTER },
+ { "maxusers", MAXUSERS },
+ { "minor", MINOR },
+#if MACHINE_I386
+ { "net", NET },
+#endif MACHINE_I386
+ { "nexus", NEXUS },
+ { "on", ON },
+ { "options", OPTIONS },
+#if MACHINE_I386
+ { "port", PORT },
+#endif MACHINE_I386
+ { "priority", PRIORITY },
+ { "pseudo-device",PSEUDO_DEVICE },
+ { "root", ROOT },
+#if MACHINE_HP300 || MACHINE_LUNA68K
+ { "scode", NEXUS },
+#endif
+ { "sequential", SEQUENTIAL },
+ { "size", SIZE },
+ { "slave", SLAVE },
+ { "swap", SWAP },
+ { "tape", DEVICE },
+#if MACHINE_I386
+ { "tty", TTY },
+#endif MACHINE_I386
+ { "timezone", TIMEZONE },
+ { "trace", TRACE },
+ { "vector", VECTOR },
+ { 0, 0 },
+};
+%}
+WORD [A-Za-z_][-A-Za-z_]*
+%%
+{WORD} {
+ int i;
+
+ if ((i = kw_lookup(yytext)) == -1)
+ {
+ yylval.str = yytext;
+ tprintf("id(%s) ", yytext);
+ return ID;
+ }
+ tprintf("(%s) ", yytext);
+ return i;
+ }
+\"[^"]+\" {
+ yytext[strlen(yytext)-1] = '\0';
+ yylval.str = yytext + 1;
+ return ID;
+ }
+0[0-7]* {
+ yylval.val = octal(yytext);
+ tprintf("#O:%o ", yylval.val);
+ return NUMBER;
+ }
+0x[0-9a-fA-F]+ {
+ yylval.val = hex(yytext);
+ tprintf("#X:%x ", yylval.val);
+ return NUMBER;
+ }
+[1-9][0-9]* {
+ yylval.val = atoi(yytext);
+ tprintf("#D:%d ", yylval.val);
+ return NUMBER;
+ }
+[0-9]"."[0-9]* {
+ double atof();
+ yylval.val = (int) (60 * atof(yytext) + 0.5);
+ return FPNUMBER;
+ }
+"-" {
+ return MINUS;
+ }
+"?" {
+ yylval.val = -1;
+ tprintf("? ");
+ return NUMBER;
+ }
+\n/[ \t] {
+ yyline++;
+ tprintf("\n... ");
+ }
+\n {
+ yyline++;
+ tprintf("\n");
+ return SEMICOLON;
+ }
+#.* { /* Ignored (comment) */; }
+[ \t]* { /* Ignored (white space) */; }
+";" { return SEMICOLON; }
+"," { return COMMA; }
+"=" { return EQUALS; }
+"@" { return AT; }
+. { return yytext[0]; }
+
+%%
+/*
+ * kw_lookup
+ * Look up a string in the keyword table. Returns a -1 if the
+ * string is not a keyword otherwise it returns the keyword number
+ */
+
+kw_lookup(word)
+register char *word;
+{
+ register struct kt *kp;
+
+ for (kp = key_words; kp->kt_name != 0; kp++)
+ if (eq(word, kp->kt_name))
+ return kp->kt_val;
+ return -1;
+}
+
+/*
+ * Number conversion routines
+ */
+
+octal(str)
+char *str;
+{
+ int num;
+
+ (void) sscanf(str, "%o", &num);
+ return num;
+}
+
+hex(str)
+char *str;
+{
+ int num;
+
+ (void) sscanf(str+2, "%x", &num);
+ return num;
+}
diff --git a/usr.sbin/config/main.c b/usr.sbin/config/main.c
new file mode 100644
index 0000000..76c2200
--- /dev/null
+++ b/usr.sbin/config/main.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 1980, 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, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <stdio.h>
+#include <ctype.h>
+#include "y.tab.h"
+#include "config.h"
+
+static char *PREFIX;
+
+/*
+ * Config builds a set of files for building a UNIX
+ * system given a description of the desired system.
+ */
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+
+ extern char *optarg;
+ extern int optind;
+ struct stat buf;
+ int ch;
+ char *p;
+
+ while ((ch = getopt(argc, argv, "gp")) != EOF)
+ switch (ch) {
+ case 'g':
+ debugging++;
+ break;
+ case 'p':
+ profiling++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1) {
+usage: fputs("usage: config [-gp] sysname\n", stderr);
+ exit(1);
+ }
+
+ if (freopen(PREFIX = *argv, "r", stdin) == NULL) {
+ perror(PREFIX);
+ exit(2);
+ }
+#ifdef CONFIG_DONT_CLOBBER
+ if (stat(p = path((char *)NULL), &buf)) {
+#else /* CONFIG_DONT_CLOBBER */
+ p = path((char *)NULL);
+ if (stat(p, &buf)) {
+#endif /* CONFIG_DONT_CLOBBER */
+ if (mkdir(p, 0777)) {
+ perror(p);
+ exit(2);
+ }
+ }
+ else if ((buf.st_mode & S_IFMT) != S_IFDIR) {
+ fprintf(stderr, "config: %s isn't a directory.\n", p);
+ exit(2);
+#ifndef CONFIG_DONT_CLOBBER
+ }
+ else {
+ char tmp[strlen(p) + 8];
+
+ fprintf(stderr, "Removing old directory %s: ", p);
+ fflush(stderr);
+ sprintf(tmp, "rm -rf %s", p);
+ if (system(tmp)) {
+ fprintf(stderr, "Failed!\n");
+ perror(tmp);
+ exit(2);
+ }
+ fprintf(stderr, "Done.\n");
+ if (mkdir(p, 0777)) {
+ perror(p);
+ exit(2);
+ }
+#endif /* CONFIG_DONT_CLOBBER */
+ }
+
+ loadaddress = -1;
+ dtab = NULL;
+ confp = &conf_list;
+ compp = &comp_list;
+ if (yyparse())
+ exit(3);
+ switch (machine) {
+
+ case MACHINE_VAX:
+ vax_ioconf(); /* Print ioconf.c */
+ ubglue(); /* Create ubglue.s */
+ break;
+
+ case MACHINE_TAHOE:
+ tahoe_ioconf();
+ vbglue();
+ break;
+
+ case MACHINE_HP300:
+ case MACHINE_LUNA68K:
+ hp300_ioconf();
+ hpglue();
+ break;
+
+ case MACHINE_I386:
+ i386_ioconf(); /* Print ioconf.c */
+ vector(); /* Create vector.s */
+ break;
+
+ case MACHINE_MIPS:
+ case MACHINE_PMAX:
+ pmax_ioconf();
+ break;
+
+ case MACHINE_NEWS3400:
+ news_ioconf();
+ break;
+
+ default:
+ printf("Specify machine type, e.g. ``machine vax''\n");
+ exit(1);
+ }
+ /*
+ * make symbolic links in compilation directory
+ * for "sys" (to make genassym.c work along with #include <sys/xxx>)
+ * and similarly for "machine".
+ */
+ {
+ char xxx[80];
+
+ (void) sprintf(xxx, "../../%s/include", machinename);
+ (void) symlink(xxx, path("machine"));
+ }
+ makefile(); /* build Makefile */
+ headers(); /* make a lot of .h files */
+ swapconf(); /* swap config files */
+ printf("Don't forget to run \"make depend\"\n");
+ exit(0);
+}
+
+/*
+ * get_word
+ * returns EOF on end of file
+ * NULL on end of line
+ * pointer to the word otherwise
+ */
+char *
+get_word(fp)
+ register FILE *fp;
+{
+ static char line[80];
+ register int ch;
+ register char *cp;
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch != ' ' && ch != '\t')
+ break;
+ if (ch == EOF)
+ return ((char *)EOF);
+ if (ch == '\n')
+ return (NULL);
+ cp = line;
+ *cp++ = ch;
+ while ((ch = getc(fp)) != EOF) {
+ if (isspace(ch))
+ break;
+ *cp++ = ch;
+ }
+ *cp = 0;
+ if (ch == EOF)
+ return ((char *)EOF);
+ (void) ungetc(ch, fp);
+ return (line);
+}
+
+/*
+ * get_quoted_word
+ * like get_word but will accept something in double or single quotes
+ * (to allow embedded spaces).
+ */
+char *
+get_quoted_word(fp)
+ register FILE *fp;
+{
+ static char line[256];
+ register int ch;
+ register char *cp;
+
+ while ((ch = getc(fp)) != EOF)
+ if (ch != ' ' && ch != '\t')
+ break;
+ if (ch == EOF)
+ return ((char *)EOF);
+ if (ch == '\n')
+ return (NULL);
+ cp = line;
+ if (ch == '"' || ch == '\'') {
+ register int quote = ch;
+
+ while ((ch = getc(fp)) != EOF) {
+ if (ch == quote)
+ break;
+ if (ch == '\n') {
+ *cp = 0;
+ printf("config: missing quote reading `%s'\n",
+ line);
+ exit(2);
+ }
+ *cp++ = ch;
+ }
+ } else {
+ *cp++ = ch;
+ while ((ch = getc(fp)) != EOF) {
+ if (isspace(ch))
+ break;
+ *cp++ = ch;
+ }
+ if (ch != EOF)
+ (void) ungetc(ch, fp);
+ }
+ *cp = 0;
+ if (ch == EOF)
+ return ((char *)EOF);
+ return (line);
+}
+
+/*
+ * prepend the path to a filename
+ */
+char *
+path(file)
+ char *file;
+{
+ register char *cp;
+
+#define CDIR "../../compile/"
+ cp = malloc((unsigned int)(sizeof(CDIR) + strlen(PREFIX) +
+ (file ? strlen(file) : 0) + 2));
+ (void) strcpy(cp, CDIR);
+ (void) strcat(cp, PREFIX);
+ if (file) {
+ (void) strcat(cp, "/");
+ (void) strcat(cp, file);
+ }
+ return (cp);
+}
diff --git a/usr.sbin/config/mkglue.c b/usr.sbin/config/mkglue.c
new file mode 100644
index 0000000..b36870e
--- /dev/null
+++ b/usr.sbin/config/mkglue.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 1980, 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[] = "@(#)mkglue.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Make the bus adaptor interrupt glue files.
+ */
+#include <stdio.h>
+#include "config.h"
+#include "y.tab.h"
+#include <ctype.h>
+
+/*
+ * Create the UNIBUS interrupt vector glue file.
+ */
+ubglue()
+{
+ register FILE *fp, *gp;
+ register struct device *dp, *mp;
+
+ fp = fopen(path("ubglue.s"), "w");
+ if (fp == 0) {
+ perror(path("ubglue.s"));
+ exit(1);
+ }
+ gp = fopen(path("ubvec.s"), "w");
+ if (gp == 0) {
+ perror(path("ubvec.s"));
+ exit(1);
+ }
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != (struct device *)-1 &&
+ !eq(mp->d_name, "mba")) {
+ struct idlst *id, *id2;
+
+ for (id = dp->d_vec; id; id = id->id_next) {
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id2 == id) {
+ dump_ubavec(fp, id->id,
+ dp->d_unit);
+ break;
+ }
+ if (!strcmp(id->id, id2->id))
+ break;
+ }
+ }
+ }
+ }
+ dump_std(fp, gp);
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != (struct device *)-1 &&
+ !eq(mp->d_name, "mba")) {
+ struct idlst *id, *id2;
+
+ for (id = dp->d_vec; id; id = id->id_next) {
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id2 == id) {
+ dump_intname(fp, id->id,
+ dp->d_unit);
+ break;
+ }
+ if (!strcmp(id->id, id2->id))
+ break;
+ }
+ }
+ }
+ }
+ dump_ctrs(fp);
+ (void) fclose(fp);
+ (void) fclose(gp);
+}
+
+static int cntcnt = 0; /* number of interrupt counters allocated */
+
+/*
+ * Print a UNIBUS interrupt vector.
+ */
+dump_ubavec(fp, vector, number)
+ register FILE *fp;
+ char *vector;
+ int number;
+{
+ char nbuf[80];
+ register char *v = nbuf;
+
+ (void) sprintf(v, "%s%d", vector, number);
+ fprintf(fp, "\t.globl\t_X%s\n\t.align\t2\n_X%s:\n\tpushr\t$0x3f\n",
+ v, v);
+ fprintf(fp, "\tincl\t_fltintrcnt+(4*%d)\n", cntcnt++);
+ if (strncmp(vector, "dzx", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdzdma\n\n", number);
+ else if (strncmp(vector, "dpx", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdpxdma\n\n", number);
+ else if (strncmp(vector, "dpr", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdprdma\n\n", number);
+ else {
+ if (strncmp(vector, "uur", 3) == 0) {
+ fprintf(fp, "#ifdef UUDMA\n");
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjsb\tuudma\n", number);
+ fprintf(fp, "#endif\n");
+ }
+ fprintf(fp, "\tpushl\t$%d\n", number);
+ fprintf(fp, "\tcalls\t$1,_%s\n\tpopr\t$0x3f\n", vector);
+ fprintf(fp, "\tincl\t_cnt+V_INTR\n\trei\n\n");
+ }
+}
+
+/*
+ * Create the VERSAbus interrupt vector glue file.
+ */
+vbglue()
+{
+ register FILE *fp, *gp;
+ register struct device *dp, *mp;
+
+ fp = fopen(path("vbglue.s"), "w");
+ if (fp == 0) {
+ perror(path("vbglue.s"));
+ exit(1);
+ }
+ gp = fopen(path("vbvec.s"), "w");
+ if (gp == 0) {
+ perror(path("vbvec.s"));
+ exit(1);
+ }
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ struct idlst *id, *id2;
+
+ mp = dp->d_conn;
+ if (mp == 0 || mp == (struct device *)-1 ||
+ eq(mp->d_name, "mba"))
+ continue;
+ for (id = dp->d_vec; id; id = id->id_next)
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id == id2) {
+ dump_vbavec(fp, id->id, dp->d_unit);
+ break;
+ }
+ if (eq(id->id, id2->id))
+ break;
+ }
+ }
+ dump_std(fp, gp);
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != (struct device *)-1 &&
+ !eq(mp->d_name, "mba")) {
+ struct idlst *id, *id2;
+
+ for (id = dp->d_vec; id; id = id->id_next) {
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id2 == id) {
+ dump_intname(fp, id->id,
+ dp->d_unit);
+ break;
+ }
+ if (eq(id->id, id2->id))
+ break;
+ }
+ }
+ }
+ }
+ dump_ctrs(fp);
+ (void) fclose(fp);
+ (void) fclose(gp);
+}
+
+/*
+ * Print a VERSAbus interrupt vector
+ */
+dump_vbavec(fp, vector, number)
+ register FILE *fp;
+ char *vector;
+ int number;
+{
+ char nbuf[80];
+ register char *v = nbuf;
+
+ (void) sprintf(v, "%s%d", vector, number);
+ fprintf(fp, "SCBVEC(%s):\n", v);
+ fprintf(fp, "\tCHECK_SFE(4)\n");
+ fprintf(fp, "\tSAVE_FPSTAT(4)\n");
+ fprintf(fp, "\tPUSHR\n");
+ fprintf(fp, "\tincl\t_fltintrcnt+(4*%d)\n", cntcnt++);
+ fprintf(fp, "\tpushl\t$%d\n", number);
+ fprintf(fp, "\tcallf\t$8,_%s\n", vector);
+ fprintf(fp, "\tincl\t_cnt+V_INTR\n");
+ fprintf(fp, "\tPOPR\n");
+ fprintf(fp, "\tREST_FPSTAT\n");
+ fprintf(fp, "\trei\n\n");
+}
+
+/*
+ * HP9000/300 interrupts are auto-vectored.
+ * Code is hardwired in locore.s
+ */
+hpglue() {}
+
+static char *vaxinames[] = {
+ "clock", "cnr", "cnx", "tur", "tux",
+ "mba0", "mba1", "mba2", "mba3",
+ "uba0", "uba1", "uba2", "uba3"
+};
+static char *tahoeinames[] = {
+ "clock", "cnr", "cnx", "rmtr", "rmtx", "buserr",
+};
+static struct stdintrs {
+ char **si_names; /* list of standard interrupt names */
+ int si_n; /* number of such names */
+} stdintrs[] = {
+ { vaxinames, sizeof (vaxinames) / sizeof (vaxinames[0]) },
+ { tahoeinames, (sizeof (tahoeinames) / sizeof (tahoeinames[0])) }
+};
+/*
+ * Start the interrupt name table with the names
+ * of the standard vectors not directly associated
+ * with a bus. Also, dump the defines needed to
+ * reference the associated counters into a separate
+ * file which is prepended to locore.s.
+ */
+dump_std(fp, gp)
+ register FILE *fp, *gp;
+{
+ register struct stdintrs *si = &stdintrs[machine-1];
+ register char **cpp;
+ register int i;
+
+ fprintf(fp, "\n\t.globl\t_intrnames\n");
+ fprintf(fp, "\n\t.globl\t_eintrnames\n");
+ fprintf(fp, "\t.data\n");
+ fprintf(fp, "_intrnames:\n");
+ cpp = si->si_names;
+ for (i = 0; i < si->si_n; i++) {
+ register char *cp, *tp;
+ char buf[80];
+
+ cp = *cpp;
+ if (cp[0] == 'i' && cp[1] == 'n' && cp[2] == 't') {
+ cp += 3;
+ if (*cp == 'r')
+ cp++;
+ }
+ for (tp = buf; *cp; cp++)
+ if (islower(*cp))
+ *tp++ = toupper(*cp);
+ else
+ *tp++ = *cp;
+ *tp = '\0';
+ fprintf(gp, "#define\tI_%s\t%d\n", buf, i*sizeof (long));
+ fprintf(fp, "\t.asciz\t\"%s\"\n", *cpp);
+ cpp++;
+ }
+}
+
+dump_intname(fp, vector, number)
+ register FILE *fp;
+ char *vector;
+ int number;
+{
+ register char *cp = vector;
+
+ fprintf(fp, "\t.asciz\t\"");
+ /*
+ * Skip any "int" or "intr" in the name.
+ */
+ while (*cp)
+ if (cp[0] == 'i' && cp[1] == 'n' && cp[2] == 't') {
+ cp += 3;
+ if (*cp == 'r')
+ cp++;
+ } else {
+ putc(*cp, fp);
+ cp++;
+ }
+ fprintf(fp, "%d\"\n", number);
+}
+
+/*
+ * Reserve space for the interrupt counters.
+ */
+dump_ctrs(fp)
+ register FILE *fp;
+{
+ struct stdintrs *si = &stdintrs[machine-1];
+
+ fprintf(fp, "_eintrnames:\n");
+ fprintf(fp, "\n\t.globl\t_intrcnt\n");
+ fprintf(fp, "\n\t.globl\t_eintrcnt\n");
+ fprintf(fp, "\t.align 2\n");
+ fprintf(fp, "_intrcnt:\n");
+ fprintf(fp, "\t.space\t4 * %d\n", si->si_n);
+ fprintf(fp, "_fltintrcnt:\n");
+ fprintf(fp, "\t.space\t4 * %d\n", cntcnt);
+ fprintf(fp, "_eintrcnt:\n\n");
+ fprintf(fp, "\t.text\n");
+}
+
+/*
+ * Create the ISA interrupt vector glue file.
+ *
+ * The interrupt handlers are hardwired into vector.s and are attached
+ * at runtime depending on the data in ioconf.c and on the results of
+ * probing. Here we only need to generate the names of the interrupt
+ * handlers in an ancient form suitable for vmstat (the _eintrcnt label
+ * can't be expressed in C). We give the names of all devices to
+ * simplify the correspondence between devices and interrupt handlers.
+ * The order must match that in mkioconf.c.
+ */
+vector()
+{
+ int dev_id;
+ FILE *fp;
+
+ fp = fopen(path("vector.h"), "w");
+ if (fp == NULL) {
+ perror(path("vector.h"));
+ exit(1);
+ }
+ fprintf(fp, "/*\n");
+ fprintf(fp, " * vector.h\n");
+ fprintf(fp, " * Macros for interrupt vector routines\n");
+ fprintf(fp, " * Generated by config program\n");
+ fprintf(fp, " */\n\n");
+ fprintf(fp, "#define\tDEVICE_NAMES \"\\\n");
+ fprintf(fp, "clk0 irqnn\\0\\\n");
+#ifdef STATCLOCK
+ /*
+ * XXX _all_ devices should be configured so that there is no need
+ * for kludges like this.
+ */
+ fprintf(fp, "rtc0 irqnn\\0\\\n");
+ dev_id = 2;
+#else
+ dev_id = 1;
+#endif
+ vector_devtab(fp, "bio", &dev_id);
+ vector_devtab(fp, "tty", &dev_id);
+ vector_devtab(fp, "net", &dev_id);
+ vector_devtab(fp, "null", &dev_id);
+ fprintf(fp, "\"\n\n");
+ fprintf(fp, "#define\tNR_DEVICES\t%d\n", dev_id);
+ (void) fclose(fp);
+}
+
+vector_devtab(fp, table, dev_idp)
+ FILE *fp;
+ char *table;
+ int *dev_idp;
+{
+ register struct device *dp, *mp;
+
+ for (dp = dtab; dp != NULL; dp = dp->d_next) {
+ if (dp->d_unit == QUES || !eq(dp->d_mask, table))
+ continue;
+ mp = dp->d_conn;
+ if (mp == NULL || mp == TO_NEXUS || !eq(mp->d_name, "isa"))
+ continue;
+ fprintf(fp, "%s%d irqnn\\0\\\n", dp->d_name, dp->d_unit);
+ (*dev_idp)++;
+ }
+}
+
diff --git a/usr.sbin/config/mkheaders.c b/usr.sbin/config/mkheaders.c
new file mode 100644
index 0000000..7929987
--- /dev/null
+++ b/usr.sbin/config/mkheaders.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 1980, 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[] = "@(#)mkheaders.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Make all the .h files for the optional entries
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "config.h"
+#include "y.tab.h"
+
+headers()
+{
+ register struct file_list *fl;
+
+ for (fl = ftab; fl != 0; fl = fl->f_next)
+ if (fl->f_needs != 0)
+ do_count(fl->f_needs, fl->f_needs, 1);
+}
+
+/*
+ * count all the devices of a certain type and recurse to count
+ * whatever the device is connected to
+ */
+do_count(dev, hname, search)
+ register char *dev, *hname;
+ int search;
+{
+ register struct device *dp, *mp;
+ register int count, hicount;
+
+ /*
+ * After this loop, "count" will be the actual number of units,
+ * and "hicount" will be the highest unit declared. do_header()
+ * must use this higher of these values.
+ */
+ for (hicount = count = 0, dp = dtab; dp != 0; dp = dp->d_next)
+ if (dp->d_unit != -1 && eq(dp->d_name, dev)) {
+ if (dp->d_type == PSEUDO_DEVICE) {
+ count =
+ dp->d_slave != UNKNOWN ? dp->d_slave : 1;
+ break;
+ }
+ count++;
+ /*
+ * Allow holes in unit numbering,
+ * assumption is unit numbering starts
+ * at zero.
+ */
+ if (dp->d_unit + 1 > hicount)
+ hicount = dp->d_unit + 1;
+ if (search) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != TO_NEXUS &&
+ mp->d_conn != 0 && mp->d_conn != TO_NEXUS) {
+ do_count(mp->d_name, hname, 0);
+ search = 0;
+ }
+ }
+ }
+ do_header(dev, hname, count > hicount ? count : hicount);
+}
+
+do_header(dev, hname, count)
+ char *dev, *hname;
+ int count;
+{
+ char *file, *name, *inw, *toheader(), *tomacro();
+ struct file_list *fl, *fl_head, *tflp;
+ FILE *inf, *outf;
+ int inc, oldcount;
+
+ file = toheader(hname);
+ name = tomacro(dev);
+ inf = fopen(file, "r");
+ oldcount = -1;
+ if (inf == 0) {
+ outf = fopen(file, "w");
+ if (outf == 0) {
+ perror(file);
+ exit(1);
+ }
+ fprintf(outf, "#define %s %d\n", name, count);
+ (void) fclose(outf);
+ return;
+ }
+ fl_head = NULL;
+ for (;;) {
+ char *cp;
+ if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
+ break;
+ if ((inw = get_word(inf)) == 0 || inw == (char *)EOF)
+ break;
+ inw = ns(inw);
+ cp = get_word(inf);
+ if (cp == 0 || cp == (char *)EOF)
+ break;
+ inc = atoi(cp);
+ if (eq(inw, name)) {
+ oldcount = inc;
+ inc = count;
+ }
+ cp = get_word(inf);
+ if (cp == (char *)EOF)
+ break;
+ fl = (struct file_list *) malloc(sizeof *fl);
+ bzero(fl, sizeof(*fl));
+ fl->f_fn = inw;
+ fl->f_type = inc;
+ fl->f_next = fl_head;
+ fl_head = fl;
+ }
+ (void) fclose(inf);
+ if (count == oldcount) {
+ for (fl = fl_head; fl != NULL; fl = tflp) {
+ tflp = fl->f_next;
+ free(fl);
+ }
+ return;
+ }
+ if (oldcount == -1) {
+ fl = (struct file_list *) malloc(sizeof *fl);
+ bzero(fl, sizeof(*fl));
+ fl->f_fn = name;
+ fl->f_type = count;
+ fl->f_next = fl_head;
+ fl_head = fl;
+ }
+ outf = fopen(file, "w");
+ if (outf == 0) {
+ perror(file);
+ exit(1);
+ }
+ for (fl = fl_head; fl != NULL; fl = tflp) {
+ fprintf(outf,
+ "#define %s %u\n", fl->f_fn, count ? fl->f_type : 0);
+ tflp = fl->f_next;
+ free(fl);
+ }
+ (void) fclose(outf);
+}
+
+/*
+ * convert a dev name to a .h file name
+ */
+char *
+toheader(dev)
+ char *dev;
+{
+ static char hbuf[80];
+
+ (void) strcpy(hbuf, path(dev));
+ (void) strcat(hbuf, ".h");
+ return (hbuf);
+}
+
+/*
+ * convert a dev name to a macro name
+ */
+char *tomacro(dev)
+ register char *dev;
+{
+ static char mbuf[20];
+ register char *cp;
+
+ cp = mbuf;
+ *cp++ = 'N';
+ while (*dev)
+ *cp++ = islower(*dev) ? toupper(*dev++) : *dev++;
+ *cp++ = 0;
+ return (mbuf);
+}
diff --git a/usr.sbin/config/mkioconf.c b/usr.sbin/config/mkioconf.c
new file mode 100644
index 0000000..c34c15b
--- /dev/null
+++ b/usr.sbin/config/mkioconf.c
@@ -0,0 +1,1117 @@
+/*
+ * Copyright (c) 1980, 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[] = "@(#)mkioconf.c 8.2 (Berkeley) 1/21/94";
+#endif /* not lint */
+
+#include <stdio.h>
+#include "y.tab.h"
+#include "config.h"
+
+/*
+ * build the ioconf.c file
+ */
+char *qu();
+char *intv();
+char *wnum();
+void pseudo_ioconf();
+
+#if MACHINE_VAX
+vax_ioconf()
+{
+ register struct device *dp, *mp, *np;
+ register int uba_n, slave;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "#include \"vax/include/pte.h\"\n");
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "#include \"sys/buf.h\"\n");
+ fprintf(fp, "#include \"sys/map.h\"\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#include \"vax/mba/mbavar.h\"\n");
+ fprintf(fp, "#include \"vax/uba/ubavar.h\"\n\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#define C (caddr_t)\n\n");
+ /*
+ * First print the mba initialization structures
+ */
+ if (seen_mba) {
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp == 0 || mp == TO_NEXUS ||
+ !eq(mp->d_name, "mba"))
+ continue;
+ fprintf(fp, "extern struct mba_driver %sdriver;\n",
+ dp->d_name);
+ }
+ fprintf(fp, "\nstruct mba_device mbdinit[] = {\n");
+ fprintf(fp, "\t/* Device, Unit, Mba, Drive, Dk */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || mp == 0 ||
+ mp == TO_NEXUS || !eq(mp->d_name, "mba"))
+ continue;
+ if (dp->d_addr) {
+ printf("can't specify csr address on mba for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_vec != 0) {
+ printf("can't specify vector for %s%d on mba\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive == UNKNOWN) {
+ printf("drive not specified for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_slave != UNKNOWN) {
+ printf("can't specify slave number for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ fprintf(fp, "\t{ &%sdriver, %d, %s,",
+ dp->d_name, dp->d_unit, qu(mp->d_unit));
+ fprintf(fp, " %s, %d },\n",
+ qu(dp->d_drive), dp->d_dk);
+ }
+ fprintf(fp, "\t0\n};\n\n");
+ /*
+ * Print the mbsinit structure
+ * Driver Controller Unit Slave
+ */
+ fprintf(fp, "struct mba_slave mbsinit [] = {\n");
+ fprintf(fp, "\t/* Driver, Ctlr, Unit, Slave */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ /*
+ * All slaves are connected to something which
+ * is connected to the massbus.
+ */
+ if ((mp = dp->d_conn) == 0 || mp == TO_NEXUS)
+ continue;
+ np = mp->d_conn;
+ if (np == 0 || np == TO_NEXUS ||
+ !eq(np->d_name, "mba"))
+ continue;
+ fprintf(fp, "\t{ &%sdriver, %s",
+ mp->d_name, qu(mp->d_unit));
+ fprintf(fp, ", %2d, %s },\n",
+ dp->d_unit, qu(dp->d_slave));
+ }
+ fprintf(fp, "\t0\n};\n\n");
+ }
+ /*
+ * Now generate interrupt vectors for the unibus
+ */
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_vec != 0) {
+ struct idlst *ip;
+ mp = dp->d_conn;
+ if (mp == 0 || mp == TO_NEXUS ||
+ (!eq(mp->d_name, "uba") && !eq(mp->d_name, "bi")))
+ continue;
+ fprintf(fp,
+ "extern struct uba_driver %sdriver;\n",
+ dp->d_name);
+ fprintf(fp, "extern ");
+ ip = dp->d_vec;
+ for (;;) {
+ fprintf(fp, "X%s%d()", ip->id, dp->d_unit);
+ ip = ip->id_next;
+ if (ip == 0)
+ break;
+ fprintf(fp, ", ");
+ }
+ fprintf(fp, ";\n");
+ fprintf(fp, "int\t (*%sint%d[])() = { ", dp->d_name,
+ dp->d_unit);
+ ip = dp->d_vec;
+ for (;;) {
+ fprintf(fp, "X%s%d", ip->id, dp->d_unit);
+ ip = ip->id_next;
+ if (ip == 0)
+ break;
+ fprintf(fp, ", ");
+ }
+ fprintf(fp, ", 0 } ;\n");
+ }
+ }
+ fprintf(fp, "\nstruct uba_ctlr ubminit[] = {\n");
+ fprintf(fp, "/*\t driver,\tctlr,\tubanum,\talive,\tintr,\taddr */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_type != CONTROLLER || mp == TO_NEXUS || mp == 0 ||
+ !eq(mp->d_name, "uba"))
+ continue;
+ if (dp->d_vec == 0) {
+ printf("must specify vector for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr == 0) {
+ printf("must specify csr address for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives need their own entries; dont ");
+ printf("specify drive or slave for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_flags) {
+ printf("controllers (e.g. %s%d) ",
+ dp->d_name, dp->d_unit);
+ printf("don't have flags, only devices do\n");
+ continue;
+ }
+ fprintf(fp,
+ "\t{ &%sdriver,\t%d,\t%s,\t0,\t%sint%d, C 0%o },\n",
+ dp->d_name, dp->d_unit, qu(mp->d_unit),
+ dp->d_name, dp->d_unit, dp->d_addr);
+ }
+ fprintf(fp, "\t0\n};\n");
+/* unibus devices */
+ fprintf(fp, "\nstruct uba_device ubdinit[] = {\n");
+ fprintf(fp,
+"\t/* driver, unit, ctlr, ubanum, slave, intr, addr, dk, flags*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
+ mp == TO_NEXUS || mp->d_type == MASTER ||
+ eq(mp->d_name, "mba"))
+ continue;
+ np = mp->d_conn;
+ if (np != 0 && np != TO_NEXUS && eq(np->d_name, "mba"))
+ continue;
+ np = 0;
+ if (eq(mp->d_name, "uba")) {
+ if (dp->d_vec == 0) {
+ printf("must specify vector for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr == 0) {
+ printf("must specify csr for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives/slaves can be specified ");
+ printf("only for controllers, ");
+ printf("not for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ uba_n = mp->d_unit;
+ slave = QUES;
+ } else {
+ if ((np = mp->d_conn) == 0) {
+ printf("%s%d isn't connected to anything ",
+ mp->d_name, mp->d_unit);
+ printf(", so %s%d is unattached\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ uba_n = np->d_unit;
+ if (dp->d_drive == UNKNOWN) {
+ printf("must specify ``drive number'' ");
+ printf("for %s%d\n", dp->d_name, dp->d_unit);
+ continue;
+ }
+ /* NOTE THAT ON THE UNIBUS ``drive'' IS STORED IN */
+ /* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
+ if (dp->d_slave != UNKNOWN) {
+ printf("slave numbers should be given only ");
+ printf("for massbus tapes, not for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_vec != 0) {
+ printf("interrupt vectors should not be ");
+ printf("given for drive %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr != 0) {
+ printf("csr addresses should be given only ");
+ printf("on controllers, not on %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ slave = dp->d_drive;
+ }
+ fprintf(fp, "\t{ &%sdriver, %2d, %s,",
+ eq(mp->d_name, "uba") ? dp->d_name : mp->d_name, dp->d_unit,
+ eq(mp->d_name, "uba") ? " -1" : qu(mp->d_unit));
+ fprintf(fp, " %s, %2d, %s, C 0%-6o, %d, 0x%x },\n",
+ qu(uba_n), slave, intv(dp), dp->d_addr, dp->d_dk,
+ dp->d_flags);
+ }
+ fprintf(fp, "\t0\n};\n");
+ pseudo_ioconf(fp);
+ (void) fclose(fp);
+}
+#endif
+
+#if MACHINE_TAHOE
+tahoe_ioconf()
+{
+ register struct device *dp, *mp, *np;
+ register int vba_n, slave;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "#include \"tahoe/include/pte.h\"\n");
+ fprintf(fp, "#include \"sys/buf.h\"\n");
+ fprintf(fp, "#include \"sys/map.h\"\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#include \"tahoe/vba/vbavar.h\"\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#define C (caddr_t)\n\n");
+ /*
+ * Now generate interrupt vectors for the versabus
+ */
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp == 0 || mp == TO_NEXUS || !eq(mp->d_name, "vba"))
+ continue;
+ if (dp->d_vec != 0) {
+ struct idlst *ip;
+ fprintf(fp,
+ "extern struct vba_driver %sdriver;\n",
+ dp->d_name);
+ fprintf(fp, "extern ");
+ ip = dp->d_vec;
+ for (;;) {
+ fprintf(fp, "X%s%d()", ip->id, dp->d_unit);
+ ip = ip->id_next;
+ if (ip == 0)
+ break;
+ fprintf(fp, ", ");
+ }
+ fprintf(fp, ";\n");
+ fprintf(fp, "int\t (*%sint%d[])() = { ", dp->d_name,
+ dp->d_unit);
+ ip = dp->d_vec;
+ for (;;) {
+ fprintf(fp, "X%s%d", ip->id, dp->d_unit);
+ ip = ip->id_next;
+ if (ip == 0)
+ break;
+ fprintf(fp, ", ");
+ }
+ fprintf(fp, ", 0 } ;\n");
+ } else if (dp->d_type == DRIVER) /* devices w/o interrupts */
+ fprintf(fp,
+ "extern struct vba_driver %sdriver;\n",
+ dp->d_name);
+ }
+ fprintf(fp, "\nstruct vba_ctlr vbminit[] = {\n");
+ fprintf(fp, "/*\t driver,\tctlr,\tvbanum,\talive,\tintr,\taddr */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_type != CONTROLLER || mp == TO_NEXUS || mp == 0 ||
+ !eq(mp->d_name, "vba"))
+ continue;
+ if (dp->d_vec == 0) {
+ printf("must specify vector for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr == 0) {
+ printf("must specify csr address for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives need their own entries; dont ");
+ printf("specify drive or slave for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_flags) {
+ printf("controllers (e.g. %s%d) ",
+ dp->d_name, dp->d_unit);
+ printf("don't have flags, only devices do\n");
+ continue;
+ }
+ fprintf(fp,
+ "\t{ &%sdriver,\t%d,\t%s,\t0,\t%sint%d, C 0x%x },\n",
+ dp->d_name, dp->d_unit, qu(mp->d_unit),
+ dp->d_name, dp->d_unit, dp->d_addr);
+ }
+ fprintf(fp, "\t0\n};\n");
+/* versabus devices */
+ fprintf(fp, "\nstruct vba_device vbdinit[] = {\n");
+ fprintf(fp,
+"\t/* driver, unit, ctlr, vbanum, slave, intr, addr, dk, flags*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
+ mp == TO_NEXUS || mp->d_type == MASTER ||
+ eq(mp->d_name, "mba"))
+ continue;
+ np = mp->d_conn;
+ if (np != 0 && np != TO_NEXUS && eq(np->d_name, "mba"))
+ continue;
+ np = 0;
+ if (eq(mp->d_name, "vba")) {
+ if (dp->d_vec == 0)
+ printf(
+ "Warning, no interrupt vector specified for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ if (dp->d_addr == 0) {
+ printf("must specify csr for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives/slaves can be specified ");
+ printf("only for controllers, ");
+ printf("not for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ vba_n = mp->d_unit;
+ slave = QUES;
+ } else {
+ if ((np = mp->d_conn) == 0) {
+ printf("%s%d isn't connected to anything ",
+ mp->d_name, mp->d_unit);
+ printf(", so %s%d is unattached\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ vba_n = np->d_unit;
+ if (dp->d_drive == UNKNOWN) {
+ printf("must specify ``drive number'' ");
+ printf("for %s%d\n", dp->d_name, dp->d_unit);
+ continue;
+ }
+ /* NOTE THAT ON THE UNIBUS ``drive'' IS STORED IN */
+ /* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
+ if (dp->d_slave != UNKNOWN) {
+ printf("slave numbers should be given only ");
+ printf("for massbus tapes, not for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_vec != 0) {
+ printf("interrupt vectors should not be ");
+ printf("given for drive %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr != 0) {
+ printf("csr addresses should be given only ");
+ printf("on controllers, not on %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ slave = dp->d_drive;
+ }
+ fprintf(fp, "\t{ &%sdriver, %2d, %s,",
+ eq(mp->d_name, "vba") ? dp->d_name : mp->d_name, dp->d_unit,
+ eq(mp->d_name, "vba") ? " -1" : qu(mp->d_unit));
+ fprintf(fp, " %s, %2d, %s, C 0x%-6x, %d, 0x%x },\n",
+ qu(vba_n), slave, intv(dp), dp->d_addr, dp->d_dk,
+ dp->d_flags);
+ }
+ fprintf(fp, "\t0\n};\n");
+ pseudo_ioconf(fp);
+ (void) fclose(fp);
+}
+#endif
+
+#if MACHINE_HP300 || MACHINE_LUNA68K
+hp300_ioconf()
+{
+ register struct device *dp, *mp;
+ register int hpib, slave;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "#include \"sys/buf.h\"\n");
+ fprintf(fp, "#include \"sys/map.h\"\n");
+ fprintf(fp, "\n");
+ if (machine == MACHINE_HP300)
+ fprintf(fp, "#include \"hp/dev/device.h\"\n\n");
+ else
+ fprintf(fp, "#include \"luna68k/dev/device.h\"\n\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#define C (caddr_t)\n");
+ fprintf(fp, "#define D (struct driver *)\n\n");
+ /*
+ * First print the hpib controller initialization structures
+ */
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || mp == 0)
+ continue;
+ fprintf(fp, "extern struct driver %sdriver;\n", dp->d_name);
+ }
+ fprintf(fp, "\nstruct hp_ctlr hp_cinit[] = {\n");
+ fprintf(fp, "/*\tdriver,\t\tunit,\talive,\taddr,\tflags */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES ||
+ dp->d_type != MASTER && dp->d_type != CONTROLLER)
+ continue;
+ if (mp != TO_NEXUS) {
+ printf("%s%s must be attached to an sc (nexus)\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("can't specify drive/slave for %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ fprintf(fp,
+ "\t{ &%sdriver,\t%d,\t0,\tC 0x%x,\t0x%x },\n",
+ dp->d_name, dp->d_unit, dp->d_addr, dp->d_flags);
+ }
+ fprintf(fp, "\t0\n};\n");
+/* devices */
+ fprintf(fp, "\nstruct hp_device hp_dinit[] = {\n");
+ fprintf(fp,
+ "/*driver,\tcdriver,\tunit,\tctlr,\tslave,\taddr,\tdk,\tflags*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp == 0 || dp->d_type != DEVICE || hpbadslave(mp, dp))
+ continue;
+ if (mp == TO_NEXUS) {
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("can't specify drive/slave for %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ slave = QUES;
+ hpib = QUES;
+ } else {
+ if (dp->d_addr != 0) {
+ printf("can't specify sc for device %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ if (mp->d_type == CONTROLLER) {
+ if (dp->d_drive == UNKNOWN) {
+ printf("must specify drive for %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ slave = dp->d_drive;
+ } else {
+ if (dp->d_slave == UNKNOWN) {
+ printf("must specify slave for %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ slave = dp->d_slave;
+ }
+ hpib = mp->d_unit;
+ }
+ fprintf(fp, "{ &%sdriver,\t", dp->d_name);
+ if (mp == TO_NEXUS)
+ fprintf(fp, "D 0x0,\t");
+ else
+ fprintf(fp, "&%sdriver,", mp->d_name);
+ fprintf(fp, "\t%d,\t%d,\t%d,\tC 0x%x,\t%d,\t0x%x },\n",
+ dp->d_unit, hpib, slave,
+ dp->d_addr, dp->d_dk, dp->d_flags);
+ }
+ fprintf(fp, "0\n};\n");
+ pseudo_ioconf(fp);
+ (void) fclose(fp);
+}
+
+#define ishpibdev(n) (eq(n,"rd") || eq(n,"ct") || eq(n,"mt") || eq(n,"ppi"))
+#define isscsidev(n) (eq(n,"sd") || eq(n,"st") || eq(n,"ac"))
+
+hpbadslave(mp, dp)
+ register struct device *dp, *mp;
+{
+
+ if (mp == TO_NEXUS && ishpibdev(dp->d_name) ||
+ mp != TO_NEXUS && eq(mp->d_name, "hpib") &&
+ !ishpibdev(dp->d_name)) {
+ printf("%s%s must be attached to an hpib\n",
+ dp->d_name, wnum(dp->d_unit));
+ return (1);
+ }
+ if (mp == TO_NEXUS && isscsidev(dp->d_name) ||
+ mp != TO_NEXUS && eq(mp->d_name, "scsi") &&
+ !isscsidev(dp->d_name)) {
+ printf("%s%s must be attached to a scsi\n",
+ dp->d_name, wnum(dp->d_unit));
+ return (1);
+ }
+ return (0);
+}
+#endif
+
+#if MACHINE_I386
+char *shandler();
+char *sirq();
+
+i386_ioconf()
+{
+ register struct device *dp, *mp, *np;
+ register int uba_n, slave;
+ int dev_id;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "/*\n");
+ fprintf(fp, " * ioconf.c \n");
+ fprintf(fp, " * Generated by config program\n");
+ fprintf(fp, " */\n\n");
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#define C (caddr_t)\n\n");
+ /*
+ * First print the isa initialization structures
+ */
+ if (seen_isa) {
+ int seen_wdc = 0, seen_fdc = 0;
+
+ fprintf(fp, "/*\n");
+ fprintf(fp, " * ISA devices\n");
+ fprintf(fp, " */\n\n");
+ fprintf(fp, "#include \"i386/isa/isa_device.h\"\n");
+ fprintf(fp, "#include \"i386/isa/isa.h\"\n");
+ fprintf(fp, "#include \"i386/isa/icu.h\"\n\n");
+ fprintf(fp, "/*\n");
+ fprintf(fp, " * XXX misplaced external declarations.\n");
+ fprintf(fp, " */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp == 0 || mp == TO_NEXUS ||
+ !eq(mp->d_name, "isa"))
+ continue;
+ fprintf(fp, "extern struct isa_driver %3.3sdriver;",
+ dp->d_name);
+ if(eq(dp->d_name, "wdc")) seen_wdc++;
+ if(eq(dp->d_name, "fdc")) seen_fdc++;
+ if (dp->d_irq == 2)
+ {
+ fprintf(stderr, "remapped irq 2 to irq 9, please update your config file\n");
+ dp->d_irq = 9;
+ }
+ if (dp->d_vec != NULL && dp->d_vec->id != NULL)
+ fprintf(fp, " inthand2_t %s;", shandler(dp));
+ fprintf(fp, "\n");
+ }
+#ifdef STATCLOCK
+ dev_id = 2;
+#else
+ dev_id = 1;
+#endif
+ isa_devtab(fp, "bio", &dev_id);
+ if(seen_wdc)
+ isa_biotab(fp, "wdc");
+ if(seen_fdc)
+ isa_biotab(fp, "fdc");
+ isa_devtab(fp, "tty", &dev_id);
+ isa_devtab(fp, "net", &dev_id);
+ isa_devtab(fp, "null", &dev_id);
+ }
+ /* XXX David did this differently!!! */
+ /* pseudo_ioconf(fp); */
+ (void) fclose(fp);
+}
+
+isa_biotab(fp, table)
+ FILE *fp;
+ char *table;
+{
+ register struct device *dp, *mp;
+
+ fprintf(fp, "\n\nstruct isa_device isa_biotab_%s[] = {\n", table);
+ fprintf(fp, "\
+/* id driver iobase irq drq maddr msiz intr unit flags drive*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || mp == 0 ||
+ mp == TO_NEXUS || !eq(mp->d_name, table))
+ continue;
+ fprintf(fp, "{ -1, &%3.3sdriver, %8.8s,",
+ mp->d_name, mp->d_port);
+ fprintf(fp, "%6.6s, %2d, C 0x%05X, %5d, %8.8s, %2d, 0x%04X, %2d },\n",
+ sirq(mp->d_irq), mp->d_drq, mp->d_maddr,
+ mp->d_msize, shandler(mp), dp->d_unit,
+ dp->d_flags, dp->d_drive);
+ }
+ fprintf(fp, "0\n};\n");
+}
+
+/*
+ * Generized routine for isa bus device table, instead of repeating
+ * all this 4 times, call this with the table argument.
+ *
+ * 4/26/93 rgrimes
+ */
+isa_devtab(fp, table, dev_idp)
+ FILE *fp;
+ char *table;
+ int *dev_idp;
+{
+ register struct device *dp, *mp;
+
+ fprintf(fp, "\n\nstruct isa_device isa_devtab_%s[] = {\n", table);
+ fprintf(fp, "\
+/* id driver iobase irq drq maddr msiz intr unit flags */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_unit == QUES || !eq(dp->d_mask, table))
+ continue;
+ mp = dp->d_conn;
+ if (mp == NULL || mp == TO_NEXUS || !eq(mp->d_name, "isa"))
+ continue;
+ fprintf(fp, "{ %2d, &%3.3sdriver,", (*dev_idp)++, dp->d_name);
+ if (dp->d_port)
+ fprintf(fp, " %8.8s,", dp->d_port);
+ else
+ fprintf(fp, " 0x%04x,", dp->d_portn);
+ fprintf(fp, "%6.6s, %2d, C 0x%05X, %5d, %8.8s, %2d, 0x%04X },\n",
+ sirq(dp->d_irq), dp->d_drq, dp->d_maddr,
+ dp->d_msize, shandler(dp), dp->d_unit,
+ dp->d_flags);
+ }
+ fprintf(fp, "0\n};\n");
+}
+
+/*
+ * XXX - there should be a general function to print devtabs instead of these
+ * little pieces of it.
+ */
+
+char *
+shandler(dp)
+ register struct device *dp;
+{
+ static char buf[32 + 1];
+
+ if (dp->d_vec == NULL || dp->d_vec->id == NULL)
+ return "NULL";
+ /*
+ * This is for ISA. We only support one interrupt handler in the
+ * devtabs. Handlers in the config file after the first for each
+ * device are ignored. Special handlers may be registered at
+ * runtime.
+ */
+ sprintf(buf, "%.32s", dp->d_vec->id);
+ return (buf);
+}
+
+char *
+sirq(num)
+{
+
+ if (num == -1)
+ return ("0");
+ sprintf(errbuf, "IRQ%d", num);
+ return (errbuf);
+}
+#endif
+
+#if MACHINE_PMAX
+pmax_ioconf()
+{
+ register struct device *dp, *mp;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "#include \"sys/types.h\"\n");
+ fprintf(fp, "#include \"sys/time.h\"\n");
+ fprintf(fp, "#include \"pmax/dev/device.h\"\n\n");
+ fprintf(fp, "#define C (char *)\n\n");
+
+ /* print controller initialization structures */
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_type == PSEUDO_DEVICE)
+ continue;
+ fprintf(fp, "extern struct driver %sdriver;\n", dp->d_name);
+ }
+ fprintf(fp, "\nstruct pmax_ctlr pmax_cinit[] = {\n");
+ fprintf(fp, "/*\tdriver,\t\tunit,\taddr,\t\tpri,\tflags */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_type != CONTROLLER && dp->d_type != MASTER)
+ continue;
+ if (dp->d_conn != TO_NEXUS) {
+ printf("%s%s must be attached to a nexus (internal bus)\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("can't specify drive/slave for %s%s\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ if (dp->d_unit == UNKNOWN || dp->d_unit == QUES)
+ dp->d_unit = 0;
+ fprintf(fp,
+ "\t{ &%sdriver,\t%d,\tC 0x%x,\t%d,\t0x%x },\n",
+ dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri,
+ dp->d_flags);
+ }
+ fprintf(fp, "\t0\n};\n");
+
+ /* print devices connected to other controllers */
+ fprintf(fp, "\nstruct scsi_device scsi_dinit[] = {\n");
+ fprintf(fp,
+ "/*driver,\tcdriver,\tunit,\tctlr,\tdrive,\tslave,\tdk,\tflags*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_type == CONTROLLER || dp->d_type == MASTER ||
+ dp->d_type == PSEUDO_DEVICE)
+ continue;
+ mp = dp->d_conn;
+ if (mp == 0 ||
+ !eq(mp->d_name, "asc") && !eq(mp->d_name, "sii")) {
+ printf("%s%s: devices must be attached to a SCSI (asc or sii) controller\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ if ((unsigned)dp->d_drive > 6) {
+ printf("%s%s: SCSI drive must be in the range 0..6\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ /* may want to allow QUES later */
+ if ((unsigned)dp->d_slave > 7) {
+ printf("%s%s: SCSI slave (LUN) must be in the range 0..7\n",
+ dp->d_name, wnum(dp->d_unit));
+ continue;
+ }
+ fprintf(fp, "{ &%sdriver,\t&%sdriver,", dp->d_name, mp->d_name);
+ fprintf(fp, "\t%d,\t%d,\t%d,\t%d,\t%d,\t0x%x },\n",
+ dp->d_unit, mp->d_unit, dp->d_drive, dp->d_slave,
+ dp->d_dk, dp->d_flags);
+ }
+ fprintf(fp, "0\n};\n");
+ pseudo_ioconf(fp);
+ (void) fclose(fp);
+}
+#endif
+
+#if MACHINE_NEWS3400
+int have_iop = 0;
+int have_hb = 0;
+int have_vme = 0;
+
+news_ioconf()
+{
+ register struct device *dp, *mp;
+ register int slave;
+ FILE *fp;
+
+ fp = fopen(path("ioconf.c"), "w");
+ if (fp == 0) {
+ perror(path("ioconf.c"));
+ exit(1);
+ }
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "#include \"sys/buf.h\"\n");
+ fprintf(fp, "#include \"sys/map.h\"\n");
+ fprintf(fp, "#include \"vm/vm.h\"\n");
+ fprintf(fp, "#include \"iop.h\"\n");
+ fprintf(fp, "#include \"hb.h\"\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#if NIOP > 0\n");
+ fprintf(fp, "#include \"news3400/iop/iopvar.h\"\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "#if NHB > 0\n");
+ fprintf(fp, "#include \"news3400/hbdev/hbvar.h\"\n");
+ fprintf(fp, "#endif\n");
+ fprintf(fp, "\n");
+ fprintf(fp, "#define C (caddr_t)\n\n");
+ fprintf(fp, "\n");
+
+/* BEGIN HB */
+ fprintf(fp, "#if NHB > 0\n");
+ /*
+ * Now generate interrupt vectors for the HYPER-BUS
+ */
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ if (dp->d_pri >= 0) {
+ mp = dp->d_conn;
+ if (mp == 0 || mp == TO_NEXUS ||
+ !eq(mp->d_name, "hb"))
+ continue;
+ fprintf(fp, "extern struct hb_driver %sdriver;\n",
+ dp->d_name);
+ have_hb++;
+ }
+ }
+ /*
+ * Now spew forth the hb_cinfo structure
+ */
+ fprintf(fp, "\nstruct hb_ctlr hminit[] = {\n");
+ fprintf(fp, "/*\t driver,\tctlr,\talive,\taddr,\tintpri */\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if ((dp->d_type != MASTER && dp->d_type != CONTROLLER)
+ || mp == TO_NEXUS || mp == 0 ||
+ !eq(mp->d_name, "hb"))
+ continue;
+ if (dp->d_pri < 0) {
+ printf("must specify priority for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives need their own entries; ");
+ printf("dont specify drive or slave for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_flags) {
+ printf("controllers (e.g. %s%d) don't have flags, ");
+ printf("only devices do\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ fprintf(fp, "\t{ &%sdriver,\t%d,\t0,\tC 0x%x,\t%d },\n",
+ dp->d_name, dp->d_unit, dp->d_addr, dp->d_pri);
+ }
+ fprintf(fp, "\t0\n};\n");
+ /*
+ * Now we go for the hb_device stuff
+ */
+ fprintf(fp, "\nstruct hb_device hdinit[] = {\n");
+ fprintf(fp,
+"\t/* driver, unit, ctlr, slave, addr, pri, dk, flags*/\n");
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (dp->d_unit == QUES || dp->d_type != DEVICE || mp == 0 ||
+ mp == TO_NEXUS || /* mp->d_type == MASTER || */
+ eq(mp->d_name, "iop") || eq(mp->d_name, "vme"))
+ continue;
+ if (eq(mp->d_name, "hb")) {
+ if (dp->d_pri < 0) {
+ printf("must specify vector for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive != UNKNOWN || dp->d_slave != UNKNOWN) {
+ printf("drives/slaves can be specified only ");
+ printf("for controllers, not for device %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ slave = QUES;
+ } else {
+ if (mp->d_conn == 0) {
+ printf("%s%d isn't connected to anything, ",
+ mp->d_name, mp->d_unit);
+ printf("so %s%d is unattached\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_drive == UNKNOWN) {
+ printf("must specify ``drive number'' for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ /* NOTE THAT ON THE IOP ``drive'' IS STORED IN */
+ /* ``SLAVE'' AND WE DON'T WANT A SLAVE SPECIFIED */
+ if (dp->d_slave != UNKNOWN) {
+ printf("slave numbers should be given only ");
+ printf("for massbus tapes, not for %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_pri >= 0) {
+ printf("interrupt priority should not be ");
+ printf("given for drive %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ if (dp->d_addr != 0) {
+ printf("csr addresses should be given only");
+ printf("on controllers, not on %s%d\n",
+ dp->d_name, dp->d_unit);
+ continue;
+ }
+ slave = dp->d_drive;
+ }
+ fprintf(fp,
+"\t{ &%sdriver, %2d, %s, %2d, C 0x%x, %d, %d, 0x%x },\n",
+ eq(mp->d_name, "hb") ? dp->d_name : mp->d_name, dp->d_unit,
+ eq(mp->d_name, "hb") ? " -1" : qu(mp->d_unit),
+ slave, dp->d_addr, dp->d_pri, dp->d_dk, dp->d_flags);
+ }
+ fprintf(fp, "\t0\n};\n\n");
+ fprintf(fp, "#endif\n\n");
+/* END HB */
+ pseudo_ioconf(fp);
+ (void) fclose(fp);
+}
+#endif
+
+char *
+intv(dev)
+ register struct device *dev;
+{
+ static char buf[20];
+
+ if (dev->d_vec == 0)
+ return (" 0");
+ (void) sprintf(buf, "%sint%d", dev->d_name, dev->d_unit);
+ return (buf);
+}
+
+char *
+qu(num)
+{
+
+ if (num == QUES)
+ return ("'?'");
+ if (num == UNKNOWN)
+ return (" -1");
+ (void) sprintf(errbuf, "%3d", num);
+ return (errbuf);
+}
+
+char *
+wnum(num)
+{
+
+ if (num == QUES || num == UNKNOWN)
+ return ("?");
+ (void) sprintf(errbuf, "%d", num);
+ return (errbuf);
+}
+
+void
+pseudo_ioconf(fp)
+ register FILE *fp;
+{
+ register struct device *dp;
+
+ (void)fprintf(fp, "\n#include <sys/device.h>\n\n");
+ for (dp = dtab; dp != NULL; dp = dp->d_next)
+ if (dp->d_type == PSEUDO_DEVICE)
+ (void)fprintf(fp, "extern void %sattach __P((int));\n",
+ dp->d_name);
+ /*
+ * XXX concatonated disks are pseudo-devices but appear as DEVICEs
+ * since they don't adhere to normal pseudo-device conventions
+ * (i.e. one entry with total count in d_slave).
+ */
+ if (seen_cd)
+ (void)fprintf(fp, "extern void cdattach __P((int));\n");
+ /* XXX temporary for HP300, others */
+ (void)fprintf(fp, "\n#include <sys/systm.h> /* XXX */\n");
+ (void)fprintf(fp, "#define etherattach (void (*)__P((int)))nullop\n");
+ (void)fprintf(fp, "#define iteattach (void (*) __P((int)))nullop\n");
+ (void)fprintf(fp, "\nstruct pdevinit pdevinit[] = {\n");
+ for (dp = dtab; dp != NULL; dp = dp->d_next)
+ if (dp->d_type == PSEUDO_DEVICE)
+ (void)fprintf(fp, "\t{ %sattach, %d },\n", dp->d_name,
+ dp->d_slave > 0 ? dp->d_slave : 1);
+ /*
+ * XXX count up cds and put out an entry
+ */
+ if (seen_cd) {
+ struct file_list *fl;
+ int cdmax = -1;
+
+ for (fl = comp_list; fl != NULL; fl = fl->f_next)
+ if (fl->f_type == COMPDEVICE && fl->f_compinfo > cdmax)
+ cdmax = fl->f_compinfo;
+ (void)fprintf(fp, "\t{ cdattach, %d },\n", cdmax+1);
+ }
+ (void)fprintf(fp, "\t{ 0, 0 }\n};\n");
+ if (seen_cd)
+ comp_config(fp);
+}
+
+comp_config(fp)
+ FILE *fp;
+{
+ register struct file_list *fl;
+ register struct device *dp;
+
+ fprintf(fp, "\n#include \"dev/cdvar.h\"\n");
+ fprintf(fp, "\nstruct cddevice cddevice[] = {\n");
+ fprintf(fp, "/*\tunit\tileave\tflags\tdk\tdevs\t\t\t\t*/\n");
+
+ fl = comp_list;
+ while (fl) {
+ if (fl->f_type != COMPDEVICE) {
+ fl = fl->f_next;
+ continue;
+ }
+ for (dp = dtab; dp != 0; dp = dp->d_next)
+ if (dp->d_type == DEVICE &&
+ eq(dp->d_name, fl->f_fn) &&
+ dp->d_unit == fl->f_compinfo)
+ break;
+ if (dp == 0)
+ continue;
+ fprintf(fp, "\t%d,\t%d,\t%d,\t%d,\t{",
+ dp->d_unit, dp->d_pri < 0 ? 0 : dp->d_pri,
+ dp->d_flags, 1);
+ for (fl = fl->f_next; fl->f_type == COMPSPEC; fl = fl->f_next)
+ fprintf(fp, " 0x%x,", fl->f_compdev);
+ fprintf(fp, " NODEV },\n");
+ }
+ fprintf(fp, "\t-1,\t0,\t0,\t0,\t{ 0 },\n};\n");
+}
+
diff --git a/usr.sbin/config/mkmakefile.c b/usr.sbin/config/mkmakefile.c
new file mode 100644
index 0000000..e76a32c
--- /dev/null
+++ b/usr.sbin/config/mkmakefile.c
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 1993, 19801990
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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[] = "@(#)mkmakefile.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Build the makefile for the system, from
+ * the information in the files files and the
+ * additional files for the machine being compiled to.
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include "y.tab.h"
+#include "config.h"
+
+#define next_word(fp, wd) \
+ { register char *word = get_word(fp); \
+ if (word == (char *)EOF) \
+ return; \
+ else \
+ wd = word; \
+ }
+#define next_quoted_word(fp, wd) \
+ { register char *word = get_quoted_word(fp); \
+ if (word == (char *)EOF) \
+ return; \
+ else \
+ wd = word; \
+ }
+
+static struct file_list *fcur;
+char *tail();
+
+/*
+ * Lookup a file, by name.
+ */
+struct file_list *
+fl_lookup(file)
+ register char *file;
+{
+ register struct file_list *fp;
+
+ for (fp = ftab ; fp != 0; fp = fp->f_next) {
+ if (eq(fp->f_fn, file))
+ return (fp);
+ }
+ return (0);
+}
+
+/*
+ * Lookup a file, by final component name.
+ */
+struct file_list *
+fltail_lookup(file)
+ register char *file;
+{
+ register struct file_list *fp;
+
+ for (fp = ftab ; fp != 0; fp = fp->f_next) {
+ if (eq(tail(fp->f_fn), tail(file)))
+ return (fp);
+ }
+ return (0);
+}
+
+/*
+ * Make a new file list entry
+ */
+struct file_list *
+new_fent()
+{
+ register struct file_list *fp;
+
+ fp = (struct file_list *) malloc(sizeof *fp);
+ bzero(fp, sizeof *fp);
+ if (fcur == 0)
+ fcur = ftab = fp;
+ else
+ fcur->f_next = fp;
+ fcur = fp;
+ return (fp);
+}
+
+static struct users {
+ int u_default;
+ int u_min;
+ int u_max;
+} users[] = {
+ { 24, 8, 1024 }, /* MACHINE_VAX */
+ { 4, 2, 128 }, /* MACHINE_TAHOE */
+ { 8, 2, 64 }, /* MACHINE_HP300 */
+ { 8, 2, 64 }, /* MACHINE_I386 */
+ { 8, 2, 64 }, /* MACHINE_MIPS */
+ { 8, 2, 64 }, /* MACHINE_PMAX */
+ { 8, 2, 64 }, /* MACHINE_LUNA68K */
+ { 8, 2, 64 }, /* MACHINE_NEWS3400 */
+};
+#define NUSERS (sizeof (users) / sizeof (users[0]))
+
+/*
+ * Build the makefile from the skeleton
+ */
+makefile()
+{
+ FILE *ifp, *ofp;
+ char line[BUFSIZ];
+ struct opt *op;
+ struct users *up;
+
+ read_files();
+ strcpy(line, "Makefile.");
+ (void) strcat(line, machinename);
+ ifp = fopen(line, "r");
+ if (ifp == 0) {
+ perror(line);
+ exit(1);
+ }
+ ofp = fopen(path("Makefile"), "w");
+ if (ofp == 0) {
+ perror(path("Makefile"));
+ exit(1);
+ }
+ fprintf(ofp, "KERN_IDENT=%s\n", raise(ident));
+ fprintf(ofp, "IDENT=-D%s", raise(ident));
+ if (profiling)
+ fprintf(ofp, " -DGPROF");
+ if (cputype == 0) {
+ printf("cpu type must be specified\n");
+ exit(1);
+ }
+ { struct cputype *cp;
+ for (cp = cputype; cp; cp = cp->cpu_next)
+ fprintf(ofp, " -D%s", cp->cpu_name);
+ }
+ for (op = opt; op; op = op->op_next)
+ if (op->op_value)
+ fprintf(ofp, " -D%s=\"%s\"", op->op_name, op->op_value);
+ else
+ fprintf(ofp, " -D%s", op->op_name);
+ fprintf(ofp, "\n");
+ if ((unsigned)machine > NUSERS) {
+ printf("maxusers config info isn't present, using vax\n");
+ up = &users[MACHINE_VAX-1];
+ } else
+ up = &users[machine-1];
+ if (maxusers == 0) {
+ printf("maxusers not specified; %d assumed\n", up->u_default);
+ maxusers = up->u_default;
+ } else if (maxusers < up->u_min) {
+ printf("minimum of %d maxusers assumed\n", up->u_min);
+ maxusers = up->u_min;
+ } else if (maxusers > up->u_max)
+ printf("warning: maxusers > %d (%d)\n", up->u_max, maxusers);
+ fprintf(ofp, "PARAM=-DTIMEZONE=%d -DDST=%d -DMAXUSERS=%d\n",
+ zone, dst, maxusers);
+ if (loadaddress != -1) {
+ fprintf(ofp, "LOAD_ADDRESS=%X\n", loadaddress);
+ }
+ for (op = mkopt; op; op = op->op_next)
+ fprintf(ofp, "%s=%s\n", op->op_name, op->op_value);
+ if (debugging)
+ fprintf(ofp, "DEBUG=-g\n");
+ if (profiling)
+ fprintf(ofp, "PROF=-pg\n");
+ while (fgets(line, BUFSIZ, ifp) != 0) {
+ if (*line != '%') {
+ fprintf(ofp, "%s", line);
+ continue;
+ }
+ if (eq(line, "%OBJS\n"))
+ do_objs(ofp);
+ else if (eq(line, "%CFILES\n"))
+ do_cfiles(ofp);
+ else if (eq(line, "%RULES\n"))
+ do_rules(ofp);
+ else if (eq(line, "%LOAD\n"))
+ do_load(ofp);
+ else
+ fprintf(stderr,
+ "Unknown %% construct in generic makefile: %s",
+ line);
+ }
+ (void) fclose(ifp);
+ (void) fclose(ofp);
+}
+
+/*
+ * Read in the information about files used in making the system.
+ * Store it in the ftab linked list.
+ */
+read_files()
+{
+ FILE *fp;
+ register struct file_list *tp, *pf;
+ register struct device *dp;
+ struct device *save_dp;
+ register struct opt *op;
+ char *wd, *this, *needs, *special;
+ char fname[32];
+ int nreqs, first = 1, configdep, isdup, std, filetype;
+
+ ftab = 0;
+ (void) strcpy(fname, "../../conf/files");
+openit:
+ fp = fopen(fname, "r");
+ if (fp == 0) {
+ perror(fname);
+ exit(1);
+ }
+ if(ident == NULL) {
+ printf("no ident line specified\n");
+ exit(1);
+ }
+next:
+ /*
+ * filename [ standard | optional ] [ config-dependent ]
+ * [ dev* | profiling-routine ] [ device-driver]
+ * [ compile-with "compile rule" ]
+ */
+ wd = get_word(fp);
+ if (wd == (char *)EOF) {
+ (void) fclose(fp);
+ if (first == 1) {
+ (void) sprintf(fname, "files.%s", machinename);
+ first++;
+ goto openit;
+ }
+ if (first == 2) {
+ (void) sprintf(fname, "files.%s", raise(ident));
+ first++;
+ fp = fopen(fname, "r");
+ if (fp != 0)
+ goto next;
+ }
+ return;
+ }
+ if (wd == 0)
+ goto next;
+ /*************************************************\
+ * If it's a comment ignore to the end of the line *
+ \*************************************************/
+ if(wd[0] == '#')
+ {
+ while( ((wd = get_word(fp)) != (char *)EOF) && wd)
+ ;
+ goto next;
+ }
+ this = ns(wd);
+ next_word(fp, wd);
+ if (wd == 0) {
+ printf("%s: No type for %s.\n",
+ fname, this);
+ exit(1);
+ }
+ if ((pf = fl_lookup(this)) && (pf->f_type != INVISIBLE || pf->f_flags))
+ isdup = 1;
+ else
+ isdup = 0;
+ tp = 0;
+ if (first == 3 && (tp = fltail_lookup(this)) != 0)
+ printf("%s: Local file %s overrides %s.\n",
+ fname, this, tp->f_fn);
+ nreqs = 0;
+ special = 0;
+ configdep = 0;
+ needs = 0;
+ std = 0;
+ filetype = NORMAL;
+ if (eq(wd, "standard"))
+ std = 1;
+ else if (!eq(wd, "optional")) {
+ printf("%s: %s must be optional or standard\n", fname, this);
+ exit(1);
+ }
+nextparam:
+ next_word(fp, wd);
+ if (wd == 0)
+ goto doneparam;
+ if (eq(wd, "config-dependent")) {
+ configdep++;
+ goto nextparam;
+ }
+ if (eq(wd, "compile-with")) {
+ next_quoted_word(fp, wd);
+ if (wd == 0) {
+ printf("%s: %s missing compile command string.\n",
+ fname);
+ exit(1);
+ }
+ special = ns(wd);
+ goto nextparam;
+ }
+ nreqs++;
+ if (eq(wd, "device-driver")) {
+ filetype = DRIVER;
+ goto nextparam;
+ }
+ if (eq(wd, "profiling-routine")) {
+ filetype = PROFILING;
+ goto nextparam;
+ }
+ if (needs == 0 && nreqs == 1)
+ needs = ns(wd);
+ if (isdup)
+ goto invis;
+ for (dp = dtab; dp != 0; save_dp = dp, dp = dp->d_next)
+ if (eq(dp->d_name, wd)) {
+ if (std && dp->d_type == PSEUDO_DEVICE &&
+ dp->d_slave <= 0)
+ dp->d_slave = 1;
+ goto nextparam;
+ }
+ if (std) {
+ dp = (struct device *) malloc(sizeof *dp);
+ init_dev(dp);
+ dp->d_name = ns(wd);
+ dp->d_type = PSEUDO_DEVICE;
+ dp->d_slave = 1;
+ save_dp->d_next = dp;
+ goto nextparam;
+ }
+ for (op = opt; op != 0; op = op->op_next)
+ if (op->op_value == 0 && opteq(op->op_name, wd)) {
+ if (nreqs == 1) {
+ free(needs);
+ needs = 0;
+ }
+ goto nextparam;
+ }
+invis:
+ while ((wd = get_word(fp)) != 0)
+ ;
+ if (tp == 0)
+ tp = new_fent();
+ tp->f_fn = this;
+ tp->f_type = INVISIBLE;
+ tp->f_needs = needs;
+ tp->f_flags = isdup;
+ tp->f_special = special;
+ goto next;
+
+doneparam:
+ if (std == 0 && nreqs == 0) {
+ printf("%s: what is %s optional on?\n",
+ fname, this);
+ exit(1);
+ }
+
+save:
+ if (wd) {
+ printf("%s: syntax error describing %s\n",
+ fname, this);
+ exit(1);
+ }
+ if (filetype == PROFILING && profiling == 0)
+ goto next;
+ if (tp == 0)
+ tp = new_fent();
+ tp->f_fn = this;
+ tp->f_type = filetype;
+ tp->f_flags = 0;
+ if (configdep)
+ tp->f_flags |= CONFIGDEP;
+ tp->f_needs = needs;
+ tp->f_special = special;
+ if (pf && pf->f_type == INVISIBLE)
+ pf->f_flags = 1; /* mark as duplicate */
+ goto next;
+}
+
+opteq(cp, dp)
+ char *cp, *dp;
+{
+ char c, d;
+
+ for (; ; cp++, dp++) {
+ if (*cp != *dp) {
+ c = isupper(*cp) ? tolower(*cp) : *cp;
+ d = isupper(*dp) ? tolower(*dp) : *dp;
+ if (c != d)
+ return (0);
+ }
+ if (*cp == 0)
+ return (1);
+ }
+}
+
+do_objs(fp)
+ FILE *fp;
+{
+ register struct file_list *tp, *fl;
+ register int lpos, len;
+ register char *cp, och, *sp;
+ char swapname[32];
+
+ fprintf(fp, "OBJS=");
+ lpos = 6;
+ for (tp = ftab; tp != 0; tp = tp->f_next) {
+ if (tp->f_type == INVISIBLE)
+ continue;
+ sp = tail(tp->f_fn);
+ for (fl = conf_list; fl; fl = fl->f_next) {
+ if (fl->f_type != SWAPSPEC)
+ continue;
+ (void) sprintf(swapname, "swap%s.c", fl->f_fn);
+ if (eq(sp, swapname))
+ goto cont;
+ }
+ cp = sp + (len = strlen(sp)) - 1;
+ och = *cp;
+ *cp = 'o';
+ if (len + lpos > 72) {
+ lpos = 8;
+ fprintf(fp, "\\\n\t");
+ }
+ fprintf(fp, "%s ", sp);
+ lpos += len + 1;
+ *cp = och;
+cont:
+ ;
+ }
+ if (lpos != 8)
+ putc('\n', fp);
+}
+
+do_cfiles(fp)
+ FILE *fp;
+{
+ register struct file_list *tp, *fl;
+ register int lpos, len;
+ char swapname[32];
+
+ fputs("CFILES=", fp);
+ lpos = 8;
+ for (tp = ftab; tp; tp = tp->f_next)
+ if (tp->f_type != INVISIBLE) {
+ len = strlen(tp->f_fn);
+ if (tp->f_fn[len - 1] != 'c')
+ continue;
+ if ((len = 3 + len) + lpos > 72) {
+ lpos = 8;
+ fputs("\\\n\t", fp);
+ }
+ fprintf(fp, "$S/%s ", tp->f_fn);
+ lpos += len + 1;
+ }
+ for (fl = conf_list; fl; fl = fl->f_next)
+ if (fl->f_type == SYSTEMSPEC) {
+ (void) sprintf(swapname, "swap%s.c", fl->f_fn);
+ if ((len = 3 + strlen(swapname)) + lpos > 72) {
+ lpos = 8;
+ fputs("\\\n\t", fp);
+ }
+ if (eq(fl->f_fn, "generic"))
+ fprintf(fp, "$S/%s/%s/%s ",
+ machinename, machinename, swapname);
+ else
+ fprintf(fp, "%s ", swapname);
+ lpos += len + 1;
+ }
+ if (lpos != 8)
+ putc('\n', fp);
+}
+
+char *
+tail(fn)
+ char *fn;
+{
+ register char *cp;
+
+ cp = rindex(fn, '/');
+ if (cp == 0)
+ return (fn);
+ return (cp+1);
+}
+
+/*
+ * Create the makerules for each file
+ * which is part of the system.
+ * Devices are processed with the special c2 option -i
+ * which avoids any problem areas with i/o addressing
+ * (e.g. for the VAX); assembler files are processed by as.
+ */
+do_rules(f)
+ FILE *f;
+{
+ register char *cp, *np, och, *tp;
+ register struct file_list *ftp;
+ char *special;
+
+ for (ftp = ftab; ftp != 0; ftp = ftp->f_next) {
+ if (ftp->f_type == INVISIBLE)
+ continue;
+ cp = (np = ftp->f_fn) + strlen(ftp->f_fn) - 1;
+ och = *cp;
+ *cp = '\0';
+ if (och == 'o') {
+ fprintf(f, "%so:\n\t-cp $S/%so .\n\n", tail(np), np);
+ continue;
+ }
+ fprintf(f, "%so: $S/%s%c\n", tail(np), np, och);
+ tp = tail(np);
+ special = ftp->f_special;
+ if (special == 0) {
+ char *ftype;
+ static char cmd[128];
+
+ switch (ftp->f_type) {
+
+ case NORMAL:
+ ftype = "NORMAL";
+ break;
+
+ case DRIVER:
+ ftype = "DRIVER";
+ break;
+
+ case PROFILING:
+ if (!profiling)
+ continue;
+ ftype = "PROFILE";
+ break;
+
+ default:
+ printf("config: don't know rules for %s\n", np);
+ break;
+ }
+ (void)sprintf(cmd, "${%s_%c%s}", ftype, toupper(och),
+ ftp->f_flags & CONFIGDEP? "_C" : "");
+ special = cmd;
+ }
+ *cp = och;
+ fprintf(f, "\t%s\n\n", special);
+ }
+}
+
+/*
+ * Create the load strings
+ */
+do_load(f)
+ register FILE *f;
+{
+ register struct file_list *fl;
+ register int first;
+ struct file_list *do_systemspec();
+
+ for (first = 1, fl = conf_list; fl; first = 0)
+ fl = fl->f_type == SYSTEMSPEC ?
+ do_systemspec(f, fl, first) : fl->f_next;
+ fputs("all:", f);
+ for (fl = conf_list; fl; fl = fl->f_next)
+ if (fl->f_type == SYSTEMSPEC)
+ fprintf(f, " %s", fl->f_needs);
+ putc('\n', f);
+}
+
+struct file_list *
+do_systemspec(f, fl, first)
+ FILE *f;
+ register struct file_list *fl;
+ int first;
+{
+
+ fprintf(f, "%s: ${SYSTEM_DEP} swap%s.o", fl->f_needs, fl->f_fn);
+ if (first)
+ fprintf(f, " vers.o");
+ fprintf(f, "\n\t${SYSTEM_LD_HEAD}\n");
+ fprintf(f, "\t${SYSTEM_LD} swap%s.o\n", fl->f_fn);
+ fprintf(f, "\t${SYSTEM_LD_TAIL}\n\n");
+ do_swapspec(f, fl->f_fn);
+ for (fl = fl->f_next; fl; fl = fl->f_next)
+ if (fl->f_type != SWAPSPEC)
+ break;
+ return (fl);
+}
+
+do_swapspec(f, name)
+ FILE *f;
+ register char *name;
+{
+
+ if (!eq(name, "generic"))
+ fprintf(f, "swap%s.o: swap%s.c\n", name, name);
+ else
+ fprintf(f, "swapgeneric.o: $S/%s/%s/swapgeneric.c\n",
+ machinename, machinename);
+ fprintf(f, "\t${NORMAL_C}\n\n");
+}
+
+char *
+raise(str)
+ register char *str;
+{
+ register char *cp = str;
+
+ while (*str) {
+ if (islower(*str))
+ *str = toupper(*str);
+ str++;
+ }
+ return (cp);
+}
+
diff --git a/usr.sbin/config/mkswapconf.c b/usr.sbin/config/mkswapconf.c
new file mode 100644
index 0000000..3cbef69
--- /dev/null
+++ b/usr.sbin/config/mkswapconf.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1980, 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[] = "@(#)mkswapconf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Build a swap configuration file.
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <ctype.h>
+
+swapconf()
+{
+ register struct file_list *fl;
+ struct file_list *do_swap();
+
+ fl = conf_list;
+ while (fl) {
+ if (fl->f_type != SYSTEMSPEC) {
+ fl = fl->f_next;
+ continue;
+ }
+ fl = do_swap(fl);
+ }
+}
+
+struct file_list *
+do_swap(fl)
+ register struct file_list *fl;
+{
+ FILE *fp;
+ char swapname[80];
+ register struct file_list *swap;
+ dev_t dev;
+
+ if (eq(fl->f_fn, "generic")) {
+ fl = fl->f_next;
+ return (fl->f_next);
+ }
+ (void) sprintf(swapname, "swap%s.c", fl->f_fn);
+ fp = fopen(path(swapname), "w");
+ if (fp == 0) {
+ perror(path(swapname));
+ exit(1);
+ }
+ fprintf(fp, "#include \"sys/param.h\"\n");
+ fprintf(fp, "#include \"sys/conf.h\"\n");
+ fprintf(fp, "\n");
+ /*
+ * If there aren't any swap devices
+ * specified, just return, the error
+ * has already been noted.
+ */
+ swap = fl->f_next;
+ if (swap == 0 || swap->f_type != SWAPSPEC) {
+ (void) unlink(path(swapname));
+ fclose(fp);
+ return (swap);
+ }
+ fprintf(fp, "dev_t\trootdev = makedev(%d, %d);\n",
+ major(fl->f_rootdev), minor(fl->f_rootdev));
+ fprintf(fp, "dev_t\tdumpdev = makedev(%d, %d);\n",
+ major(fl->f_dumpdev), minor(fl->f_dumpdev));
+ fprintf(fp, "\n");
+ fprintf(fp, "struct\tswdevt swdevt[] = {\n");
+ do {
+ dev = swap->f_swapdev;
+ fprintf(fp, "\t{ makedev(%d, %d),\t%d,\t%d },\t/* %s */\n",
+ major(dev), minor(dev), swap->f_swapflag,
+ swap->f_swapsize, swap->f_fn);
+ swap = swap->f_next;
+ } while (swap && swap->f_type == SWAPSPEC);
+ fprintf(fp, "\t{ NODEV, 0, 0 }\n");
+ fprintf(fp, "};\n");
+ fclose(fp);
+ return (swap);
+}
+
+static int devtablenotread = 1;
+static struct devdescription {
+ char *dev_name;
+ int dev_major;
+ struct devdescription *dev_next;
+} *devtable;
+
+/*
+ * Given a device name specification figure out:
+ * major device number
+ * partition
+ * device name
+ * unit number
+ * This is a hack, but the system still thinks in
+ * terms of major/minor instead of string names.
+ */
+dev_t
+nametodev(name, defunit, defpartition)
+ char *name;
+ int defunit;
+ char defpartition;
+{
+ char *cp, partition;
+ int unit;
+ register struct devdescription *dp;
+
+ cp = name;
+ if (cp == 0) {
+ fprintf(stderr, "config: internal error, nametodev\n");
+ exit(1);
+ }
+ while (*cp && !isdigit(*cp))
+ cp++;
+ unit = *cp ? atoi(cp) : defunit;
+ if (unit < 0 || unit > 31) {
+ fprintf(stderr,
+"config: %s: invalid device specification, unit out of range\n", name);
+ unit = defunit; /* carry on more checking */
+ }
+ if (*cp) {
+ *cp++ = '\0';
+ while (*cp && isdigit(*cp))
+ cp++;
+ }
+ partition = *cp ? *cp : defpartition;
+ if (partition < 'a' || partition > 'h') {
+ fprintf(stderr,
+"config: %c: invalid device specification, bad partition\n", *cp);
+ partition = defpartition; /* carry on */
+ }
+ if (devtablenotread)
+ initdevtable();
+ for (dp = devtable; dp; dp = dp->dev_next)
+ if (eq(name, dp->dev_name))
+ break;
+ if (dp == 0) {
+ fprintf(stderr, "config: %s: unknown device\n", name);
+ return (NODEV);
+ }
+ return (makedev(dp->dev_major, (unit << 3) + (partition - 'a')));
+}
+
+char *
+devtoname(dev)
+ dev_t dev;
+{
+ char buf[80];
+ register struct devdescription *dp;
+
+ if (devtablenotread)
+ initdevtable();
+ for (dp = devtable; dp; dp = dp->dev_next)
+ if (major(dev) == dp->dev_major)
+ break;
+ if (dp == 0)
+ dp = devtable;
+ (void) sprintf(buf, "%s%d%c", dp->dev_name,
+ minor(dev) >> 3, (minor(dev) & 07) + 'a');
+ return (ns(buf));
+}
+
+initdevtable()
+{
+ char linebuf[256];
+ char buf[BUFSIZ];
+ int maj;
+ register struct devdescription **dp = &devtable;
+ FILE *fp;
+
+ (void) sprintf(buf, "../conf/devices.%s", machinename);
+ fp = fopen(buf, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "config: can't open %s\n", buf);
+ exit(1);
+ }
+ while(fgets(linebuf,256,fp)) {
+ /*******************************\
+ * Allow a comment *
+ \*******************************/
+ if(linebuf[0] == '#') continue;
+
+ if (sscanf(linebuf, "%s\t%d\n", buf, &maj) == 2) {
+ *dp = (struct devdescription *)malloc(sizeof (**dp));
+ (*dp)->dev_name = ns(buf);
+ (*dp)->dev_major = maj;
+ dp = &(*dp)->dev_next;
+ } else {
+ fprintf(stderr,"illegal line in devices file\n");
+ break;
+ }
+ }
+ *dp = 0;
+ fclose(fp);
+ devtablenotread = 0;
+}
diff --git a/usr.sbin/config/mkubglue.c b/usr.sbin/config/mkubglue.c
new file mode 100644
index 0000000..7d2b3d4
--- /dev/null
+++ b/usr.sbin/config/mkubglue.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 1980, 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[] = "@(#)mkubglue.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * Make the uba interrupt file ubglue.s
+ */
+#include <stdio.h>
+#include "config.h"
+#include "y.tab.h"
+
+ubglue()
+{
+ register FILE *fp;
+ register struct device *dp, *mp;
+
+ fp = fopen(path("ubglue.s"), "w");
+ if (fp == 0) {
+ perror(path("ubglue.s"));
+ exit(1);
+ }
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != (struct device *)-1 &&
+ !eq(mp->d_name, "mba")) {
+ struct idlst *id, *id2;
+
+ for (id = dp->d_vec; id; id = id->id_next) {
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id2 == id) {
+ dump_vec(fp, id->id, dp->d_unit);
+ break;
+ }
+ if (!strcmp(id->id, id2->id))
+ break;
+ }
+ }
+ }
+ }
+ dump_std(fp);
+ for (dp = dtab; dp != 0; dp = dp->d_next) {
+ mp = dp->d_conn;
+ if (mp != 0 && mp != (struct device *)-1 &&
+ !eq(mp->d_name, "mba")) {
+ struct idlst *id, *id2;
+
+ for (id = dp->d_vec; id; id = id->id_next) {
+ for (id2 = dp->d_vec; id2; id2 = id2->id_next) {
+ if (id2 == id) {
+ dump_intname(fp, id->id,
+ dp->d_unit);
+ break;
+ }
+ if (!strcmp(id->id, id2->id))
+ break;
+ }
+ }
+ }
+ }
+ dump_ctrs(fp);
+ (void) fclose(fp);
+}
+
+static int cntcnt = 0; /* number of interrupt counters allocated */
+
+/*
+ * print an interrupt vector
+ */
+dump_vec(fp, vector, number)
+ register FILE *fp;
+ char *vector;
+ int number;
+{
+ char nbuf[80];
+ register char *v = nbuf;
+
+ (void) sprintf(v, "%s%d", vector, number);
+ fprintf(fp, "\t.globl\t_X%s\n\t.align\t2\n_X%s:\n\tpushr\t$0x3f\n",
+ v, v);
+ fprintf(fp, "\tincl\t_fltintrcnt+(4*%d)\n", cntcnt++);
+ if (strncmp(vector, "dzx", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdzdma\n\n", number);
+ else if (strncmp(vector, "dpx", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdpxdma\n\n", number);
+ else if (strncmp(vector, "dpr", 3) == 0)
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjmp\tdprdma\n\n", number);
+ else {
+ if (strncmp(vector, "uur", 3) == 0) {
+ fprintf(fp, "#ifdef UUDMA\n");
+ fprintf(fp, "\tmovl\t$%d,r0\n\tjsb\tuudma\n", number);
+ fprintf(fp, "#endif\n");
+ }
+ fprintf(fp, "\tpushl\t$%d\n", number);
+ fprintf(fp, "\tcalls\t$1,_%s\n\tpopr\t$0x3f\n", vector);
+ fprintf(fp, "\tincl\t_cnt+V_INTR\n\trei\n\n");
+ }
+}
+
+/*
+ * Start the interrupt name table with the names
+ * of the standard vectors not on the unibus.
+ * The number and order of these names should correspond
+ * with the definitions in scb.s.
+ */
+dump_std(fp)
+ register FILE *fp;
+{
+ fprintf(fp, "\n\t.globl\t_intrnames\n");
+ fprintf(fp, "\n\t.globl\t_eintrnames\n");
+ fprintf(fp, "\t.data\n");
+ fprintf(fp, "_intrnames:\n");
+ fprintf(fp, "\t.asciz\t\"clock\"\n");
+ fprintf(fp, "\t.asciz\t\"cnr\"\n");
+ fprintf(fp, "\t.asciz\t\"cnx\"\n");
+ fprintf(fp, "\t.asciz\t\"tur\"\n");
+ fprintf(fp, "\t.asciz\t\"tux\"\n");
+ fprintf(fp, "\t.asciz\t\"mba0\"\n");
+ fprintf(fp, "\t.asciz\t\"mba1\"\n");
+ fprintf(fp, "\t.asciz\t\"mba2\"\n");
+ fprintf(fp, "\t.asciz\t\"mba3\"\n");
+ fprintf(fp, "\t.asciz\t\"uba0\"\n");
+ fprintf(fp, "\t.asciz\t\"uba1\"\n");
+ fprintf(fp, "\t.asciz\t\"uba2\"\n");
+ fprintf(fp, "\t.asciz\t\"uba3\"\n");
+#define I_FIXED 13 /* number of names above */
+}
+
+dump_intname(fp, vector, number)
+ register FILE *fp;
+ char *vector;
+ int number;
+{
+ register char *cp = vector;
+
+ fprintf(fp, "\t.asciz\t\"");
+ /*
+ * Skip any "int" or "intr" in the name.
+ */
+ while (*cp)
+ if (cp[0] == 'i' && cp[1] == 'n' && cp[2] == 't') {
+ cp += 3;
+ if (*cp == 'r')
+ cp++;
+ } else {
+ putc(*cp, fp);
+ cp++;
+ }
+ fprintf(fp, "%d\"\n", number);
+}
+
+dump_ctrs(fp)
+ register FILE *fp;
+{
+ fprintf(fp, "_eintrnames:\n");
+ fprintf(fp, "\n\t.globl\t_intrcnt\n");
+ fprintf(fp, "\n\t.globl\t_eintrcnt\n");
+ fprintf(fp, "_intrcnt:\n", I_FIXED);
+ fprintf(fp, "\t.space\t4 * %d\n", I_FIXED);
+ fprintf(fp, "_fltintrcnt:\n", cntcnt);
+ fprintf(fp, "\t.space\t4 * %d\n", cntcnt);
+ fprintf(fp, "_eintrcnt:\n\n");
+ fprintf(fp, "\t.text\n");
+}
diff --git a/usr.sbin/cron/Makefile b/usr.sbin/cron/Makefile
new file mode 100644
index 0000000..1131cff
--- /dev/null
+++ b/usr.sbin/cron/Makefile
@@ -0,0 +1,3 @@
+SUBDIR= lib cron crontab
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/cron/cron/Makefile b/usr.sbin/cron/cron/Makefile
new file mode 100644
index 0000000..09cde80
--- /dev/null
+++ b/usr.sbin/cron/cron/Makefile
@@ -0,0 +1,18 @@
+BINDIR?= /usr/sbin
+
+PROG= cron
+SRCS= cron.c database.c do_command.c job.c user.c popen.c
+MAN3= bitstring.3
+MAN8= cron.8
+
+.if exists(${.CURDIR}/../lib/obj)
+LDDESTDIR+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libcron.a
+.else
+LDDESTDIR+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libcron.a
+.endif
+
+LDADD+= -lcron
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/cron/cron/bitstring.3 b/usr.sbin/cron/cron/bitstring.3
new file mode 100644
index 0000000..efe9ae3
--- /dev/null
+++ b/usr.sbin/cron/cron/bitstring.3
@@ -0,0 +1,168 @@
+.\" Copyright (c) 1989 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" Paul Vixie.
+.\"
+.\" 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.
+.\"
+.\" @(#)bitstring.3 5.1 (Berkeley) 12/13/89
+.\"
+.TH BITSTRING 3 "December 13, 1989"
+.UC 4
+.SH NAME
+bit_alloc, bit_clear, bit_decl, bit_ffs, bit_nclear, bit_nset,
+bit_set, bitstr_size, bit_test \- bit-string manipulation macros
+.SH SYNOPSIS
+.ft B
+.nf
+#include <bitstring.h>
+
+name = bit_alloc(nbits)
+bitstr_t *name;
+int nbits;
+
+bit_decl(name, nbits)
+bitstr_t name;
+int nbits;
+
+bit_clear(name, bit)
+bitstr_t name;
+int bit;
+
+bit_ffc(name, nbits, value)
+bitstr_t name;
+int nbits, *value;
+
+bit_ffs(name, nbits, value)
+bitstr_t name;
+int nbits, *value;
+
+bit_nclear(name, start, stop)
+bitstr_t name;
+int start, stop;
+
+bit_nset(name, start, stop)
+bitstr_t name;
+int start, stop;
+
+bit_set(name, bit)
+bitstr_t name;
+int bit;
+
+bitstr_size(nbits)
+int nbits;
+
+bit_test(name, bit)
+bitstr_t name;
+int bit;
+.fi
+.ft R
+.SH DESCRIPTION
+These macros operate on strings of bits.
+.PP
+.I Bit_alloc
+returns a pointer of type
+.I bitstr_t\ *
+to sufficient space to store
+.I nbits
+bits, or NULL if no space is available.
+.PP
+.I Bit_decl
+is a macro for allocating sufficient space to store
+.I nbits
+bits on the stack.
+.PP
+.I Bitstr_size
+returns the number of elements of type
+.I bitstr_t
+necessary to store
+.I nbits
+bits.
+This is useful for copying bit strings.
+.PP
+.I Bit_clear
+and
+.I bit_set
+clear or set the zero-based numbered bit
+.IR bit ,
+in the bit string
+.IR name .
+.PP
+.I Bit_nset
+and
+.I bit_nclear
+set or clear the zero-based numbered bits from
+.I start
+to
+.I stop
+in the bit string
+.IR name .
+.PP
+.I Bit_test
+evaluates to zero if the zero-based numbered bit
+.I bit
+of bit string
+.I name
+is set, and non-zero otherwise.
+.PP
+.I Bit_ffs
+sets
+.I *value
+to the zero-based number of the first bit set in the array of
+.I nbits
+bits referenced by
+.IR name .
+If no bits are set,
+.I *value
+is set to -1.
+.PP
+.I Bit_ffc
+sets
+.I *value
+to the zero-based number of the first bit not set in the array of
+.I nbits
+bits referenced by
+.IR name .
+If all bits are set,
+.I value
+is set to -1.
+.SH EXAMPLE
+.nf
+.in +5
+#include <limits.h>
+#include <bitstring.h>
+
+...
+#define LPR_BUSY_BIT 0
+#define LPR_FORMAT_BIT 1
+#define LPR_DOWNLOAD_BIT 2
+...
+#define LPR_AVAILABLE_BIT 9
+#define LPR_MAX_BITS 10
+
+make_lpr_available()
+{
+ bitstr_t bit_decl(bitlist, LPR_MAX_BITS);
+ ...
+ bit_nclear(bitlist, 0, LPR_MAX_BITS - 1);
+ ...
+ if (!bit_test(bitlist, LPR_BUSY_BIT)) {
+ bit_clear(bitlist, LPR_FORMAT_BIT);
+ bit_clear(bitlist, LPR_DOWNLOAD_BIT);
+ bit_set(bitlist, LPR_AVAILABLE_BIT);
+ }
+}
+.fi
+.SH "SEE ALSO"
+malloc(3)
diff --git a/usr.sbin/cron/cron/bitstring.h b/usr.sbin/cron/cron/bitstring.h
new file mode 100644
index 0000000..d054de3
--- /dev/null
+++ b/usr.sbin/cron/cron/bitstring.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Paul Vixie.
+ *
+ * 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.
+ *
+ * @(#)bitstring.h 5.2 (Berkeley) 4/4/90
+ */
+
+typedef unsigned char bitstr_t;
+
+/* internal macros */
+ /* byte of the bitstring bit is in */
+#define _bit_byte(bit) \
+ ((bit) >> 3)
+
+ /* mask for the bit within its byte */
+#define _bit_mask(bit) \
+ (1 << ((bit)&0x7))
+
+/* external macros */
+ /* bytes in a bitstring of nbits bits */
+#define bitstr_size(nbits) \
+ ((((nbits) - 1) >> 3) + 1)
+
+ /* allocate a bitstring */
+#define bit_alloc(nbits) \
+ (bitstr_t *)malloc(1, \
+ (unsigned int)bitstr_size(nbits) * sizeof(bitstr_t))
+
+ /* allocate a bitstring on the stack */
+#define bit_decl(name, nbits) \
+ (name)[bitstr_size(nbits)]
+
+ /* is bit N of bitstring name set? */
+#define bit_test(name, bit) \
+ ((name)[_bit_byte(bit)] & _bit_mask(bit))
+
+ /* set bit N of bitstring name */
+#define bit_set(name, bit) \
+ (name)[_bit_byte(bit)] |= _bit_mask(bit)
+
+ /* clear bit N of bitstring name */
+#define bit_clear(name, bit) \
+ (name)[_bit_byte(bit)] &= ~_bit_mask(bit)
+
+ /* clear bits start ... stop in bitstring */
+#define bit_nclear(name, start, stop) { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ register int _startbyte = _bit_byte(_start); \
+ register int _stopbyte = _bit_byte(_stop); \
+ if (_startbyte == _stopbyte) { \
+ _name[_startbyte] &= ((0xff >> (8 - (_start&0x7))) | \
+ (0xff << ((_stop&0x7) + 1))); \
+ } else { \
+ _name[_startbyte] &= 0xff >> (8 - (_start&0x7)); \
+ while (++_startbyte < _stopbyte) \
+ _name[_startbyte] = 0; \
+ _name[_stopbyte] &= 0xff << ((_stop&0x7) + 1); \
+ } \
+}
+
+ /* set bits start ... stop in bitstring */
+#define bit_nset(name, start, stop) { \
+ register bitstr_t *_name = name; \
+ register int _start = start, _stop = stop; \
+ register int _startbyte = _bit_byte(_start); \
+ register int _stopbyte = _bit_byte(_stop); \
+ if (_startbyte == _stopbyte) { \
+ _name[_startbyte] |= ((0xff << (_start&0x7)) & \
+ (0xff >> (7 - (_stop&0x7)))); \
+ } else { \
+ _name[_startbyte] |= 0xff << ((_start)&0x7); \
+ while (++_startbyte < _stopbyte) \
+ _name[_startbyte] = 0xff; \
+ _name[_stopbyte] |= 0xff >> (7 - (_stop&0x7)); \
+ } \
+}
+
+ /* find first bit clear in name */
+#define bit_ffc(name, nbits, value) { \
+ register bitstr_t *_name = name; \
+ register int _byte, _nbits = nbits; \
+ register int _stopbyte = _bit_byte(_nbits), _value = -1; \
+ for (_byte = 0; _byte <= _stopbyte; ++_byte) \
+ if (_name[_byte] != 0xff) { \
+ _value = _byte << 3; \
+ for (_stopbyte = _name[_byte]; (_stopbyte&0x1); \
+ ++_value, _stopbyte >>= 1); \
+ break; \
+ } \
+ *(value) = _value; \
+}
+
+ /* find first bit set in name */
+#define bit_ffs(name, nbits, value) { \
+ register bitstr_t *_name = name; \
+ register int _byte, _nbits = nbits; \
+ register int _stopbyte = _bit_byte(_nbits), _value = -1; \
+ for (_byte = 0; _byte <= _stopbyte; ++_byte) \
+ if (_name[_byte]) { \
+ _value = _byte << 3; \
+ for (_stopbyte = _name[_byte]; !(_stopbyte&0x1); \
+ ++_value, _stopbyte >>= 1); \
+ break; \
+ } \
+ *(value) = _value; \
+}
diff --git a/usr.sbin/cron/cron/compat.h b/usr.sbin/cron/cron/compat.h
new file mode 100644
index 0000000..528c6d3
--- /dev/null
+++ b/usr.sbin/cron/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.8 1994/01/15 20:43:43 vixie 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/cron/config.h b/usr.sbin/cron/cron/config.h
new file mode 100644
index 0000000..7a8e2fc
--- /dev/null
+++ b/usr.sbin/cron/cron/config.h
@@ -0,0 +1,86 @@
+/* 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 2.6 1994/01/15 20:43:43 vixie 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 -or0s %s" /*-*/
+ /* -Fx = set full-name of sender
+ * -odi = Option Deliverymode Interactive
+ * -oem = Option Errors Mailedtosender
+ * -or0s = Option Readtimeout -- don't time out
+ */
+
+/* #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/cron.8 b/usr.sbin/cron/cron/cron.8
new file mode 100644
index 0000000..1d6dcda
--- /dev/null
+++ b/usr.sbin/cron/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 2.2 1993/12/28 08:34:43 vixie 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/cron.c b/usr.sbin/cron/cron/cron.c
new file mode 100644
index 0000000..624c37a
--- /dev/null
+++ b/usr.sbin/cron/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 2.11 1994/01/15 20:43:43 vixie 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/cron.h b/usr.sbin/cron/cron/cron.h
new file mode 100644
index 0000000..ebe45c7
--- /dev/null
+++ b/usr.sbin/cron/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 2.10 1994/01/15 20:43:43 vixie 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/cron/database.c b/usr.sbin/cron/cron/database.c
new file mode 100644
index 0000000..843401e
--- /dev/null
+++ b/usr.sbin/cron/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 2.8 1994/01/15 20:43:43 vixie 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/cron/do_command.c b/usr.sbin/cron/cron/do_command.c
new file mode 100644
index 0000000..4083c32
--- /dev/null
+++ b/usr.sbin/cron/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 2.12 1994/01/15 20:43:43 vixie 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) sprintf(mailcmd, MAILARGS,
+ MAILCMD, mailto);
+ 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/cron/externs.h b/usr.sbin/cron/cron/externs.h
new file mode 100644
index 0000000..3efe605
--- /dev/null
+++ b/usr.sbin/cron/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/cron/job.c b/usr.sbin/cron/cron/job.c
new file mode 100644
index 0000000..adaa072
--- /dev/null
+++ b/usr.sbin/cron/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.6 1994/01/15 20:43:43 vixie 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/cron/pathnames.h b/usr.sbin/cron/cron/pathnames.h
new file mode 100644
index 0000000..df6bf1e
--- /dev/null
+++ b/usr.sbin/cron/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.3 1994/01/15 20:43:43 vixie 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/cron/popen.c b/usr.sbin/cron/cron/popen.c
new file mode 100644
index 0000000..55708bb
--- /dev/null
+++ b/usr.sbin/cron/cron/popen.c
@@ -0,0 +1,166 @@
+/*
+ * 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.5 1994/01/15 20:43:43 vixie Exp $";
+static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 2/14/89";
+#endif /* not lint */
+
+#include "cron.h"
+#include <sys/signal.h>
+
+
+#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[100];
+#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;; 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/cron/putman.sh b/usr.sbin/cron/cron/putman.sh
new file mode 100644
index 0000000..4aef625
--- /dev/null
+++ b/usr.sbin/cron/cron/putman.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# putman.sh - install a man page according to local custom
+# vixie 27dec93 [original]
+#
+# $Id:$
+
+PAGE=$1
+DIR=$2
+
+SECT=`expr $PAGE : '[a-z]*.\([0-9]\)'`
+
+[ -d $DIR/man$SECT ] && {
+ set -x
+ cp $PAGE $DIR/man$SECT/$PAGE
+ set +x
+} || {
+ set -x
+ nroff -man $PAGE >$DIR/cat$SECT/`basename $PAGE .$SECT`.0
+ set +x
+}
+
+exit 0
diff --git a/usr.sbin/cron/cron/user.c b/usr.sbin/cron/cron/user.c
new file mode 100644
index 0000000..9672dd5
--- /dev/null
+++ b/usr.sbin/cron/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 2.8 1994/01/15 20:43:43 vixie 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/cron/crontab/Makefile b/usr.sbin/cron/crontab/Makefile
new file mode 100644
index 0000000..f8337b2
--- /dev/null
+++ b/usr.sbin/cron/crontab/Makefile
@@ -0,0 +1,19 @@
+BINDIR?= /usr/bin
+
+PROG= crontab
+SRCS= crontab.c
+CFLAGS+= -I${.CURDIR}/../cron
+MAN1= crontab.1
+MAN5= crontab.5
+
+.if exists(${.CURDIR}/../lib/obj)
+LDDESTDIR+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libcron.a
+.else
+LDDESTDIR+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libcron.a
+.endif
+
+LDADD+= -lcron
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/cron/crontab/crontab.1 b/usr.sbin/cron/crontab/crontab.1
new file mode 100644
index 0000000..c3c3943
--- /dev/null
+++ b/usr.sbin/cron/crontab/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 2.4 1993/12/31 10:47:33 vixie 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/crontab.5 b/usr.sbin/cron/crontab/crontab.5
new file mode 100644
index 0000000..01b52f0
--- /dev/null
+++ b/usr.sbin/cron/crontab/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 2.4 1994/01/15 20:43:43 vixie 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/crontab.c b/usr.sbin/cron/crontab/crontab.c
new file mode 100644
index 0000000..657af71
--- /dev/null
+++ b/usr.sbin/cron/crontab/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 2.13 1994/01/17 03:20:37 vixie 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/doc/CHANGES b/usr.sbin/cron/doc/CHANGES
new file mode 100644
index 0000000..59f6803
--- /dev/null
+++ b/usr.sbin/cron/doc/CHANGES
@@ -0,0 +1,155 @@
+Vixie Cron Changes from V2 to V3
+Paul Vixie
+29-Dec-1993
+
+The crontab command now conforms to POSIX 1003.2. This means that when you
+install it, if you have any "crontab" command lines floating around in shell
+scripts (such as /etc/rc or /etc/rc.local), you will need to change them.
+
+I have integrated several changes made by BSDi for their BSD/386 operating
+system; these were offerred to me before I started consulting for them, so
+it is safe to say that they were intended for publication. Most notably,
+the name of the cron daemon has changed from "crond" to "cron". This was
+done for compatibility with 4.3BSD. Another change made for the same reason
+is the ability to read in an /etc/crontab file which has an extra field in
+each entry, between the time fields and the command. This field is a user
+name, and it permits the /etc/crontab command to contain commands which are
+to be run by any user on the system. /etc/crontab is not "installed" via
+the crontab(1) command; it is automatically read at startup time and it will
+be reread whenever it changes.
+
+I also added a "-e" option to crontab(1). Nine people also sent me diffs
+to add this option, but I had already implemented it on my own. I actually
+released an interrim version (V2.2, I think) for limited testing, and got a
+chance to fix a bad security bug in the "-e" option thanks to XXX.
+
+The daemon used to be extraordinarily sloppy in its use of file descriptors.
+A heck of a lot of them were left open in spawned jobs, which caused problems
+for the daemon and also caused problems with the spawned jobs if they were
+shell scripts since "sh" and "csh" have traditionally used hidden file
+descriptors to pass information to subshells, and cron was causing them to
+think they were subshells. If you had trouble with "sh" or "csh" scripts in
+V2, chances are good that V3 will fix your problems.
+
+About a dozen people have reminded me that I forgot to initialize
+"crontab_fd" in database.c. Keith Cantrell was the first, so he gets the
+point.
+
+Steve Simmons reminded me that once an account has been deleted from the
+system, "crontab -u USER -d" will not work. My solution is to suggest to
+all of you that before you delete a user's account, you first delete that
+user's crontab file if any. From cron's point of view, usernames can never
+be treated as arbitrary strings. Either they are valid user names, or they
+are not. I will not make an exception for the "-d" case, for security
+reasons that I consider reasonable. It is trivial for a root user to delete
+the entry by hand if necessary.
+
+Dan O'Neil reminded me that I forgot to reset "log_fd" in misc.c. A lot of
+others also reminded me of this, but Dan gets the point. I didn't fix it
+there, since the real bug was that it should have been open in the parent.
+
+Peter Kabal reminded me that I forgot to "#ifdef DEBUGGING" some code in
+misc.c. Hans Trompert actually told me first, but Peter sent the patch so
+he gets the point.
+
+Russell Nelson told me that I'd forgotten to "#include <syslog.h>" in misc.c,
+which explains why a lot of other people complained that it wasn't using
+syslog even when they configured it that way :-). Steve Simmons told me
+first, though, so he gets the point.
+
+An interrim version of the daemon tried to "stat" every file before
+executing it; this turned out to be a horribly bad idea since finding the
+name of a file from a shell command is a hard job (that's why we have
+shells, right?) I removed this bogus code. Dave Burgess gets the point.
+
+Dennis R. Conley sent a suggestion for MMDF systems, which I've added to the
+comments in cron.h.
+
+Mike Heisler noted that I use comments in the CONVERSION file which are
+documented as illegal in the man pages. Thanks, Mike.
+
+Irving Wolfe sent me some very cheerful changes for a NeXT system, but I
+consider the system itself broken and I can't bring myself to #ifdef for
+something as screwed up as this system seems to be. However, various others
+did send me smaller patches which appear to have cause cron to build and run
+correctly on (the latest) NeXT machines, with or without the "-posix" CFLAG.
+Irving also asked for a per-job MAILTO, and this was finally added later when
+I integrated the BSD/386 changes contributed by BSDi, and generalized some of
+the parsing.
+
+Lots of folks complained that the autogenerated "Date:" header wasn't in
+ARPA format. I didn't understand this -- either folks will use Sendmail and
+not generate a Date: at all (since Sendmail will do it), or folks will use
+something other than Sendmail which won't care about Date: formats. But
+I've "fixed" it anyway...
+
+Several people suggested that "*" should be able to take a "/step". One person
+suggested that "N/step" ought to mean "N-last/step", but that's stretching things
+a bit far. "*/step" seems quite intuitive to me, so I've added it. Colin Plumb
+sent in the first and most polite request for this feature.
+
+As with every release of Cron, BIND, and seemingly everything else I do, one
+user stands out with the most critical but also the most useful analysis.
+Cron V3's high score belongs to Peter Holzer, who sent in the nicest looking
+patch for the "%" interpretation problem and also helped me understand a
+tricky bit of badness in the "log_fd" problem.
+
+agulbra@flode.nvg.unit.no wins the honors for being the first to point out the
+nasty security hole in "crontab -r". 'Nuff said.
+
+Several folks pointed out that log_it() needed to exist even if logging was
+disabled. Some day I will create a tool that will compile a subsystem with
+every possible combination and permutation of #ifdef options, but meanwhile
+thanks to everybody.
+
+job_runqueue() was using storage after freeing it, since Jordan told me back
+in 1983 that C let you do that, and I believed him in 1986 when I wrote all
+this junk. Linux was the first to die from this error, and the Linux people
+sent me the most amazing, um, collection of patches for this problem. Thanks
+for all the fish.
+
+Jeremy Bettis reminded me that popen() isn't safe. I grabbed Ken Arnold's
+version of popen/pclose from the ftpd and hacked it to taste. We're safe now,
+from this at least.
+
+Branko Lankester sent me a very timely and helpful fix for a looming security
+problem in my "crontab -e" implementation.
+
+--------
+
+Vixie Cron Changes from V1 to V2
+Paul Vixie
+8-Feb-1988
+
+Many changes were made in a rash of activity about six months ago, the exact
+list of which is no longer clear in my memory. I know that V1 used a file
+called POKECRON in /usr/spool/cron to tell it that it was time to re-read
+all the crontab files; V2 uses the modtime the crontab directory as a flag to
+check out the crontab files; those whose modtime has changed will be re-read,
+and the others left alone. Note that the crontab(1) command will do a utimes
+call to make sure the mtime of the dir changes, since the filename/inode will
+often remain the same after a replacement and the mtime wouldn't change in
+that case.
+
+8-Feb-88: made it possible to use much larger environment variable strings.
+ V1 allowed 100 characters; V2 allows 1000. This was needed for PATH
+ variables on some systems. Thanks to Toerless Eckert for this idea.
+ E-mail: UUCP: ...pyramid!fauern!faui10!eckert
+
+16-Feb-88: added allow/deny, moved /usr/spool/cron/crontabs to
+ /usr/lib/cron/tabs. allow and deny are /usr/lib/cron/{allow,deny},
+ since the sysv naming for this depends on 'at' using the same
+ dir, which would be stupid (hint: use /usr/{lib,spool}/at).
+
+22-Feb-88: made it read the spool directory for crontabs and look each one
+ up using getpwnam() rather than reading all passwds with getpwent()
+ and trying to open each crontab.
+
+9-Dec-88: made it sync to :00 after the minute, makes cron predictable.
+ added logging to /var/cron/log.
+
+14-Apr-90: (actually, changes since December 1989)
+ fixed a number of bugs reported from the net and from John Gilmore.
+ added syslog per Keith Bostic. security features including not
+ being willing to run a command owned or writable by other than
+ the owner of the crontab 9not working well yet)
diff --git a/usr.sbin/cron/doc/CONVERSION b/usr.sbin/cron/doc/CONVERSION
new file mode 100644
index 0000000..b86427d
--- /dev/null
+++ b/usr.sbin/cron/doc/CONVERSION
@@ -0,0 +1,85 @@
+$Id: CONVERSION,v 2.2 1993/12/28 08:34:43 vixie Exp $
+
+Conversion of BSD 4.[23] crontab files:
+
+Edit your current crontab (/usr/lib/crontab) into little pieces, with each
+users' commands in a different file. This is different on 4.2 and 4.3,
+but I'll get to that below. The biggest feature of this cron is that you
+can move 'news' and 'uucp' cron commands into files owned and maintainable
+by those two users. You also get to rip all the fancy 'su' footwork out
+of the cron commands. On 4.3, there's no need for the 'su' stuff since the
+user name appears on each command -- but I'd still rather have separate
+crontabs with seperate environments and so on.
+
+Leave the original /usr/lib/crontab! This cron doesn't use it, so you may
+as well keep it around for a while in case something goes wakko with this
+fancy version.
+
+Most commands in most crontabs are run by root, have to run by root, and
+should continue to be run by root. They still have to be in their own file;
+I recommend /etc/crontab.src or /usr/adm/crontab.src.
+
+'uucp's commands need their own file; how about /usr/lib/uucp/crontab.src?
+'news' also, perhaps in /usr/lib/news/crontab.src...
+
+I say `how about' and `perhaps' because it really doesn't matter to anyone
+(except you) where you put the crontab source files. The `crontab' command
+COPIES them into a protected directory (CRONDIR/SPOOL_DIR in cron.h), named
+after the user whose crontab it is. If you want to examine, replace, or
+delete a crontab, the `crontab' command does all of those things. The
+various `crontab.src' (my suggested name for them) files are just source
+files---they have to be copied to SPOOLDIR using `crontab' before they'll be
+executed.
+
+On 4.2, your crontab might have a few lines like this:
+
+ 5 * * * * su uucp < /usr/lib/uucp/uudemon.hr
+ 10 4 * * * su uucp < /usr/lib/uucp/uudemon.day
+ 15 5 * * 0 su uucp < /usr/lib/uucp/uudemon.wk
+
+...or like this:
+
+ 5 * * * * echo /usr/lib/uucp/uudemon.hr | su uucp
+ 10 4 * * * echo /usr/lib/uucp/uudemon.day | su uucp
+ 15 5 * * 0 echo /usr/lib/uucp/uudemon.wk | su uucp
+
+On 4.3, they'd look a little bit better, but not much:
+
+ 5 * * * * uucp /usr/lib/uucp/uudemon.hr
+ 10 4 * * * uucp /usr/lib/uucp/uudemon.day
+ 15 5 * * 0 uucp /usr/lib/uucp/uudemon.wk
+
+For this cron, you'd create /usr/lib/uucp/crontab.src (or wherever you want
+to keep uucp's commands) which would look like this:
+
+ # /usr/lib/uucp/crontab.src - uucp's crontab
+ #
+ PATH=/usr/lib/uucp:/bin:/usr/bin
+ SHELL=/bin/sh
+ HOME=/usr/lib/uucp
+ #
+ 5 * * * * uudemon.hr
+ 10 4 * * * uudemon.day
+ 15 5 * * 0 uudemon.wk
+
+The application to the `news' cron commands (if any) is left for you to
+figure out. Likewise if there are any other cruddy-looking 'su' commands in
+your crontab commands, you don't need them anymore: just find a good place
+to put the `crontab.src' (or whatever you want to call it) file for that
+user, put the cron commands into it, and install it using the `crontab'
+command (probably with "-u USERNAME", but see the man page).
+
+If you run a 4.2-derived cron, you could of course just install your current
+crontab in toto as root's crontab. It would work exactly the way your
+current one does, barring the extra steps in installing or changing it.
+There would still be advantages to this cron, mostly that you get mail if
+there is any output from your cron commands.
+
+One note about getting mail from cron: you will probably find, after you
+install this version of cron, that your cron commands are generating a lot
+of irritating output. The work-around for this is to redirect all EXPECTED
+output to a per-execution log file, which you can examine if you want to
+see the output from the "last time" a command was executed; if you get any
+UNEXPECTED output, it will be mailed to you. This takes a while to get
+right, but it's amazingly convenient. Trust me.
+
diff --git a/usr.sbin/cron/doc/FEATURES b/usr.sbin/cron/doc/FEATURES
new file mode 100644
index 0000000..209b1e9
--- /dev/null
+++ b/usr.sbin/cron/doc/FEATURES
@@ -0,0 +1,84 @@
+$Id: FEATURES,v 2.1 1993/12/28 08:34:43 vixie Exp $
+
+Features of Vixie's cron relative to BSD 4.[23] and SysV crons:
+
+-- Environment variables can be set in each crontab. SHELL, USER,
+ LOGNAME, and HOME are set from the user's passwd entry; all except
+ USER can be changed in the crontab. PATH is especially useful to
+ set there. TZ can be set, but cron ignores it other than passing
+ it on through to the commands it runs. Format is
+
+ variable=value
+
+ Blanks surrounding the '=' will be eaten; other blanks in value are
+ okay. Leading or trailing blanks can be preserved by quoting, single
+ or double quotes are okay, just so they match.
+
+ PATH=.:/bin:/usr/bin
+ SHELL=/bin/sh
+ FOOBAR = this is a long blanky example
+
+ Above, FOOBAR would get "this is a long blanky example" as its value.
+
+ SHELL and HOME will be used when it's time to run a command; if
+ you don't set them, HOME defaults to your /etc/passwd entry
+ and SHELL defaults to /bin/sh.
+
+ MAILTO, if set to the login name of a user on your system, will be the
+ person that cron mails the output of commands in that crontab. This is
+ useful if you decide on BINMAIL when configuring cron.h, since binmail
+ doesn't know anything about aliasing.
+
+-- Weekdays can be specified by name. Case is not significant, but only
+ the first three letters should be specified.
+
+-- Months can likewise be specified by name. Three letters only.
+
+-- Ranges and lists can be mixed. Standard crons won't allow '1,3-5'.
+
+-- Ranges can specify 'step' values. '10-16/2' is like '10,12,14,16'.
+
+-- Sunday is both day 0 and day 7 -- apparently BSD and ATT disagree
+ about this.
+
+-- Each user gets their own crontab file. This is a win over BSD 4.2,
+ where only root has one, and over BSD 4.3, where they made the crontab
+ format incompatible and although the commands can be run by non-root
+ uid's, root is still the only one who can edit the crontab file. This
+ feature mimics the SysV cron.
+
+-- The 'crontab' command is loosely compatible with SysV, but has more
+ options which just generally make more sense. Running crontab with
+ no arguments will print a cute little summary of the command syntax.
+
+-- Comments and blank lines are allowed in the crontab file. Comments
+ must be on a line by themselves; leading whitespace is ignored, and
+ a '#' introduces the comment.
+
+-- (big win) If the `crontab' command changes anything in any crontab,
+ the 'cron' daemon will reload all the tables before running the
+ next iteration. In some crons, you have to kill and restart the
+ daemon whenever you change a crontab. In other crons, the crontab
+ file is reread and reparsed every minute even if it didn't change.
+
+-- In order to support the automatic reload, the crontab files are not
+ readable or writable except by 'crontab' or 'cron'. This is not a
+ problem, since 'crontab' will let you do pretty much whatever you
+ want to your own crontab, or if you are root, to anybody's crontab.
+
+-- If any output is generated by a command (on stdout OR stderr), it will
+ be mailed to the owner of the crontab that contained the command (or
+ MAILTO, see discussion of environment variables, above). The headers
+ of the mail message will include the command that was run, and a
+ complete list of the environment that was passed to it, which will
+ contain (at least) the USER (LOGNAME on SysV), HOME, and SHELL.
+
+-- 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'. I didn't think up
+ this behaviour; it's how cron has always worked but the documentation
+ hasn't been very clear. I have been told that some AT&T crons do not
+ act this way and do the more reasonable thing, which is (IMHO) to "or"
+ the various field-matches together. In that sense this cron may not
+ be completely similar to some AT&T crons.
diff --git a/usr.sbin/cron/doc/INSTALL b/usr.sbin/cron/doc/INSTALL
new file mode 100644
index 0000000..cc660ff
--- /dev/null
+++ b/usr.sbin/cron/doc/INSTALL
@@ -0,0 +1,87 @@
+/* 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: INSTALL,v 2.5 1994/01/15 20:43:43 vixie Exp $
+
+Read the comments at the top of the Makefile, then edit the area marked
+'configurable stuff'.
+
+Edit config.h. The stuff I expect you to change is down a bit from the
+top of the file, but it's clearly marked. Also look at pathnames.h.
+
+You don't have to create the /var/cron or /var/cron/tabs directories, since
+both the daemon and the `crontab' program will do this the first time they
+run if they don't exist. You do need to have a /var, though -- just "mkdir
+/var" if you don't have one, or you can "mkdir /usr/var; ln -s /usr/var /var"
+if you expect your /var to have a lot of stuff in it.
+
+You will also need /usr/local/etc and /usr/local/bin directories unless you
+change the Makefile. These will have to be created by hand, but if you are
+a long-time Usenet user you probably have them already. /usr/local/man is
+where I keep my man pages, but I have the source for `man' and you probably
+do not. Therefore you may have to put the man pages into /usr/man/manl,
+which will be hard since there will be name collisions. (Note that the man
+command was originally written by Bill Joy before he left Berkeley, and it
+contains no AT&T code, so it is in UUNET's archive of freely-distributable
+BSD code.)
+
+LINUX note: /usr/include/paths.h on some linux systems shows _PATH_SENDMAIL
+ to be /usr/bin/sendmail even though sendmail is installed in /usr/lib.
+ you should check this out.
+
+say:
+ make all
+
+su and say:
+ make install
+
+Note that if I can get you to "su and say" something just by asking, you have
+a very serious security problem on your system and you should look into it.
+
+Edit your /usr/lib/crontab file into little pieces -- see the CONVERSION file
+for help on this.
+
+Use the `crontab' command to install all the little pieces you just created.
+Some examples (see below before trying any of these!)
+
+ crontab -u uucp -r /usr/lib/uucp/crontab.src
+ crontab -u news -r /usr/lib/news/crontab.src
+ crontab -u root -r /usr/adm/crontab.src
+
+Notes on above examples: (1) the .src files are copied at the time the
+command is issued; changing the source files later will have no effect until
+they are reinstalled with another `crontab -r' command. (2) The crontab
+command will affect the crontab of the person using the command unless `-u
+USER' is given; `-u' only works for root. When using most `su' commands
+under most BSD's, `crontab' will still think of you as yourself even though
+you may think of yourself as root -- so use `-u' liberally. (3) the `-r'
+option stands for `replace'; check the man page for crontab(1) for other
+possibilities.
+
+Kill your existing cron daemon -- do `ps aux' and look for /etc/cron.
+
+Edit your /etc/rc or /etc/rc.local, looking for the line that starts up
+/etc/cron. Comment it out and add a line to start the new cron daemon
+-- usually /usr/local/etc/cron, unless you changed it in the Makefile.
+
+Start up this cron daemon yourself as root. Just type /usr/local/etc/cron
+(or whatever); no '&' is needed since the daemon forks itself and the
+process you executed returns immediately.
+
+ATT notes: for those people unfortunate enough to be stuck on a AT&T UNIX,
+you will need the public-domain "libndir", found in the B News source and in
+any comp.sources.unix archive. You will also need to hack the code some.
diff --git a/usr.sbin/cron/doc/MAIL b/usr.sbin/cron/doc/MAIL
new file mode 100644
index 0000000..b066e7e
--- /dev/null
+++ b/usr.sbin/cron/doc/MAIL
@@ -0,0 +1,475 @@
+[ this is really old mail that came to me in response to my 1986 posting
+ to usenet asking for feature suggestions before releasing the first
+ version of cron. it is presented here for its entertainment value.
+ --vix ]
+
+$Id: MAIL,v 1.1 1993/12/28 08:30:36 vixie Exp $
+
+From ptsfa!lll-crg!ames!acornrc!bob Wed Dec 31 10:07:08 1986
+Date: Wed, 31 Dec 86 08:59:31 pst
+From: lll-crg!ames!acornrc!bob (Bob Weissman)
+To: ptsfa!vixie!paul
+Status: RO
+
+Sure, here's a suggestion: I'd like to be able to run a program, say,
+every two hours. Current cron requires me to write
+0,2,4,6,8,10,12,14,16,18,20,22 in the hours field. How about a notation
+to handle this more elegantly?
+
+<< Okay, I've allowed 0-22/2 as a means of handling this.
+ The time specification for my cron is as follows:
+ specification = range {"," range}
+ range = (start "-" finish ["/" step]) | single-unit
+ This allows "1,3,5-7", which the current cron doesn't (it won't
+ do a range inside a list), and handles your specific need. >>
+
+From drw@mit-eddie Wed Dec 31 18:25:27 1986
+Date: Wed, 31 Dec 86 14:28:19 est
+From: drw@mit-eddie (Dale Worley)
+To: mit-eddie!vixie!paul
+Status: RO
+
+We have a lot of lines in our crontab of the form
+
+ 00 12 * * * su user < /usr/users/user/script.file
+
+This barfs (silently!) on our system (Dec Ultrix 1.2 == 4.2bsd) if
+user's shell is csh. This, I am told, is because csh requires that
+the environment be set up in certain ways, which cron doesn't do.
+(Actually, I believe, it is because /etc/rc, which runs cron, doesn't
+set up the environment enough for csh to run, and cron just inherits
+the situation.) Anyway, the point is that if you find out what csh
+really needs in its environment, you might want to set up cron to
+provide some reasonable defaults (if it isn't supplied by cron's
+parent). Also, could you tell me what csh needs, if you find out, so
+we can hack our /etc/rc?
+
+<< well, the environment IS a problem. processes that cron forks
+ will inherit the environment of the person who ran the cron
+ daemon... I plan to edit out such useless things as TERMCAP,
+ TERM, and the like; supply correct values for HOME, USER, CWD,
+ and whatever else comes to mind. I'll make sure csh works... >>
+From ptsfa!ames!seismo!dgis!generous Thu Jan 1 07:33:17 1987
+Date: Thu Jan 1 10:29:20 1987
+From: ames!seismo!dgis!generous (Curtis Generous)
+To: nike!ptsfa!vixie!paul
+Status: RO
+
+Paul:
+
+One of the limitations of the present versions of cron is the lack
+of the capability of specifying a way to execute a command every
+n units of time.
+
+Here is a good example:
+
+# Present method to start up uucico
+02,12,22,32,42,52 * * * * exec /usr/lib/uucp/uucico -r1
+
+# New method ?? (the ':' here is just one possibility for syntax)
+02:10 * * * * exec /usr/lib/uucp/uucico -r1
+
+This method would prove very helpful for those programs that get started
+every few minutes, making the entry long and not easily readable. The first
+number would specify the base time, and the second number the repetition
+interval.
+
+<< Good idea, but bob@acornrc beat you to it. I used '/' instead of
+ ':'. This is my personal preference, and seems intuitive when you
+ think of the divide operator in C... Does anyone have a preference? >>
+
+From ptsfa!lll-lcc!seismo!decuac!c3pe!c3engr!charles Thu Jan 1 17:04:24 1987
+From: lll-lcc!seismo!c3pe!c3engr!charles (Charles Green)
+To: c3pe!decuac!dolqci!vrdxhq!seismo!lll-lcc!ptsfa!vixie!paul
+Date: Thu Jan 1 19:22:47 1987
+Status: RO
+
+Well, this isn't a compatible extension, but I have in times past wondered
+about a facility to let you start a process at intervals of, say, 17 minutes,
+instead of particular minutes out of each hour.
+
+<< This was a popular request! >>
+
+From seismo!uwvax!astroatc!nicmad!norvax!mann Sun Jan 4 13:04:01 1987
+Date: Fri, 2 Jan 87 09:23:53 cst
+From: lll-lcc!seismo!uwvax!astroatc!nicmad!norvax!mann (Tom Mann)
+To: ptsfa!vixie!paul
+Status: RO
+
+I'm not sure if it is in cron (either SysV or BSD ... if it is, I haven't
+figured it out ) but a comment feature would SURE BE NICE!.
+There are times when I want to comment out an entry
+for a period of time; it might also make it a lot more legible.
+
+<< My cron allows blank lines and standard #-type comments. I know
+ that one BSD4.2 cron I've used had it. I don't know about SysV. >>
+
+From ptsfa!hoptoad!hugh Mon Jan 5 10:26:46 1987
+Date: Mon, 5 Jan 87 01:22:17 PST
+From: hoptoad!hugh (Hugh Daniel)
+To: ptsfa!vixie!paul
+Status: RO
+
+ Hi, I do have a BIG one that I would like. I want to log ALL output
+from command lines into a file for each line. Thus I might have a chance
+of finding out why my crontab entry did not work.
+ This would seem to work best if done by cron, as it is now I have a google
+of shell scripts laying about just to put the error output where I can see
+it.
+
+<< My cron (and the SysV cron) will send mail to the owner of the
+ particular crontab file if a command generates any output on stdout
+ or stderr. This can be irritating, but if you write a script such
+ that any output means a problem occurred, you can avoid most logfile
+ needs, and not generate mail except in unforeseen circumstances. >>
+
+From ptsfa!dual!ucbvax!ihnp4!anvil!es!Robert_Toxen Mon Jan 5 13:08:46 1987
+From: dual!ucbvax!ihnp4!anvil!es!Robert_Toxen
+Date: Fri, 2 Jan 87 14:25:29 EST
+To: anvil!ihnp4!ucbvax!dual!ptsfa!vixie!paul
+Status: RO
+
+Here are some suggestions:
+1. Run it through the C preprocessor via "/lib/<whatever>".
+
+<< hmmm. this seems of limited utility, and if you really wanted
+ to do it that way, you could do it yourself (since users can
+ write to their own crontab files). I'll add '-' (read stdin)
+ to the crontab installer program to facilitate this. >>
+
+2. Allow specifying every Nth day of week, i.e., every second Wednesday.
+ I did this to calendar by separating the day of week (Wed=4, which one
+ to start on and N with slashes). I took modulo the day of year as a
+ starting point so that someone with a desk calendar documenting such
+ things can easily determine the offset (second number). I did this
+ while at SGI; alas I don't have a copy of the code.
+
+<< I can see how this could be useful, but I'm not sure how I'd
+ implement it. Cron currently doesn't keep track of the last time
+ a given command was run; whether the current Wednesday is the first
+ or second since the command was last run would be pretty hard to
+ figure out. I'd have to keep a database of commands and their
+ execution around, and purge it when the crontab was overwritten.
+ This is too much work for me, but if someone adds it, let me know. >>
+
+From ptsfa!ames!seismo!cbmvax!devon!paul Tue Jan 6 05:50:17 1987
+From: ames!seismo!cbmvax!devon!paul
+To: cbmvax!seismo!nike!ptsfa!vixie!paul
+Date: Mon Jan 5 09:29:57 1987
+Status: RO
+
+One problem that has always plagued me with cron is the assumed ORing.
+I'd like to see some type of ANDing implemented. I guess I can best
+describe this by example. Say I have the following line in my crontab
+file:
+
+* * 4-31 * 1-6 /usr/bin/command
+
+What this does is run 'command' on the 4th thru 31st days of the
+month, AND on Monday thru Saturday; which probably means running it
+every day of the month (unless Sunday falls on days 1-3). This
+happens because cron runs the command if the day-of-month OR the
+day-of-week is true.
+
+What I'd like to happen with the above line is to run the command ONLY
+on Monday thru Saturday any time after the 3rd of the month, e.g. if
+the day-of-month AND the day-of-week are true.
+
+My proposal to you is to implement some special chars for the first
+five fields. Examples:
+
+* * !1-3 * 1-6 /usr/bin/command
+
+(run command Mon-Sat, but NOT [!] on the first 3 days of the month)
+
+* * &4-31 * &1-6 /usr/bin/command
+
+(run command if day-of-month AND day-of-week are true)
+
+Get the picture? This would be compatable with existing versions of
+cron (which wouldn't currently be using any special characters, so
+that old crontabs would be handled correctly).
+
+<< This message made me aware of the actual boolean expression involved
+ in a crontab entry. I'd assumed that it was
+ (minute && hour && DoM && month && DoW)
+ But it's really
+ (minute && hour && month && (DoM || DoW))
+
+ I can see some value in changing this, but with a fixed order of
+ fields, operators get to be kindof unary, which && and || really
+ aren't. If someone has an idea on a syntax that allows useful
+ variations to the standard (&& && && (||)) default, please suggest. >>
+
+From bobkat!pedz Tue Jan 6 20:02:10 1987
+From: pedz@bobkat.UUCP (Pedz Thing)
+Date: 2 Jan 87 17:34:44 GMT
+Status: RO
+
+Log files! It would be nice to be able to specify a log for cron
+itself and also a log for each program's stdout and stderr to go to.
+The latter can of course be done with > and 2> but it would be nice if
+there could be a single line with some sort of pattern like
+`> /usr/spool/log/%' and the command would be substituted for the %.
+Another thing which would be nice is to be able to specify which shell
+to call to give the command to.
+
+<< Log files are done with mail. The '%' idea could be useful if
+ a different character were used (% is special to cron, see man
+ page); a different directory would have to be chosen, since each
+ user has their own crontab file; and something intelligent would
+ have to be done in the file naming, since the first word of the
+ command might be ambiguous (with other commands). In short, it's
+ too much work. Sorry. >>
+
+From guy%gorodish@sun Tue Jan 6 20:03:13 1987
+From: guy%gorodish@sun (Guy Harris)
+Message-ID: <10944@sun.uucp>
+Date: 5 Jan 87 12:09:09 GMT
+References: <429@vixie.UUCP> <359@bobkat.UUCP>
+Sender: news@sun.uucp
+Status: RO
+
+> Another thing which would be nice is to be able to specify which shell
+> to call to give the command to.
+
+Well, the obvious choice would be the user's shell, but this wouldn't work
+for accounts like "uucico".
+
+<< I use the owning user's shell, and to handle "uucico" I check a
+ list of "acceptable shells" (currently compiled in, does anybody
+ mind?), substituting a default (compiled in) shell if the user's
+ shell isn't on the list.
+
+ BTW, "compiled in" means that it's in a .h file, easily changed
+ during installation, but requiring recompilation to modify. You
+ don't have to go digging through the code to find it... >>
+
+From qantel!hplabs!ucbvax!mwm@violet.berkeley.edu Tue Jan 6 21:24:48 1987
+To: hplabs!qantel!vixie!paul (Paul Vixie Esq)
+Date: 04 Jan 87 00:42:35 PST (Sun)
+From: Mike Meyer <mwm@violet.berkeley.edu>
+Status: RO
+
+<<[Discussion of RMS/FSF, and mwm's GNU Cron deleted]>>
+
+Oh, yeah - here are the extensions on my cron:
+
+1) Sunday is both day 0 and day 7, so it complies with both SysV and
+BSD cron.
+
+<< Good idea. I did it too, thanks for informing me. >>
+
+2) At is integrated into the cron. Instead of atrun to scan the
+/usr/spool/at directory, at files are put into the /usr/lib/cron
+directory along with users cron files, and cron fabricates a line from
+a crontab file to run them. This is considered a major win by all who
+use it.
+
+<< I don't use 'at', and my cron doesn't do anything with it. To run
+ 'at', I use 'atrun' the same way the current BSD cron does. My
+ crontab files are in /usr/spool/cron/crontabs, in the SysV
+ tradition -- not in /usr/lib/cron. This is a configuration
+ parameter, of course. >>
+
+There are two known restrictions:
+
+1) I don't support any of the SysV security hooks. I don't have a use
+for them, and RMS didn't like the idea at all :-).
+
+<< This means cron.allow and cron.deny. I plan to support them, as
+ they've been quite helpful at various HPUX sites I've administered. >>
+
+2) Cron expects to be able to create files with names longer than 14
+characters, which makes it hard to run on SysV. At least one person
+was working on a port, but I don't know how it's going. That might
+make for a good reason for releasing yours, right there.
+
+<< If someone has SysV (with the 14-character limit), they probably
+ won't want my cron, since it doesn't add much to the standard
+ version (which they may have support for). My cron is not currently
+ portable to non-BSD systems, since it relies on interval timers (I
+ needed to sleep for intervals more granular than seconds alone would
+ allow). The port would be trivial, and I will do it if a lot of
+ people ask for it... >>
+
+Oh, yeah - I'm going to see about getting this cron integrated into
+the next 4BSD release.
+
+<< How does one go about this? I have a few nifty gadgets I'd like
+ to contribute, this cron being one of them... >>
+
+<<[more FSF/GNU discussion deleted]>>
+
+From qantel!hplabs!ames!ut-sally!ut-ngp!melpad!bigtex!james Tue Jan 6 21:24:57 1987
+Posted-Date: Fri, 2 Jan 87 19:26:16 est
+Date: Fri, 2 Jan 87 19:26:16 est
+From: hplabs!ames!ut-sally!ut-ngp!bigtex!james
+To: vixie!paul
+Status: RO
+
+Yes!!! There are several critical failures in System V cron...
+
+1. Pass all variables in cron's environment into the environment of things
+ cron starts up, or at least into the crontab entries started up (at jobs
+ will inherit the environment of the user). If nothing else it is critically
+ important that the TZ variable be passed on. PATH should be passed on too.
+ Basically, passing environment values allows one to design a standard
+ environment with TZ and PATH and have that run by everything. If anyone
+ tells you this is no big deal, consider what happens when uucico is
+ started by cron in CA to make a long distance phone link... Unless the
+ administrator is really on his/her toes, calls scheduled at 5pm will really
+ go at two in the afternoon, needlessly incurring huge phone bills, all
+ because System V refuses to pass the TZ from its environment down. There
+ are work arounds, but only putting it in cron will really work. This is
+ not a security hole.
+
+<< delete TERM and TERMCAP; modify HOME, USER, and CWD; pass TZ and
+ PATH through undisturbed. any other requests out there?
+
+ BSD doesn't have this problem -- TZ is passed right on through if
+ you define it in the shell before starting my cron daemon. However,
+ the BSD I'm running this on doesn't need TZ to be defined anyway...
+ The default in the kernel has been just fine so far... But just the
+ same, if/when I port to SysV (I guess I really should), I'll make
+ sure this works right.
+
+ I guess I've been spoiled. HPUX is SysV-based, and I never had a
+ problem with cron and TZ when I used it. >>
+
+2. A way to avoid logging stuff in /usr/lib/cron/log. I have a cron entry
+ run uudemon.hr every 10 minutes. This is 144 times/day. Each run generates
+ three lines of text, for a total of 432 lines of text I don't want to see.
+ Obviously this should be optional, but it would be nice if there were a
+ way to flag an entry so that it wasn't logged at all unless there was an
+ error.
+
+<< I don't know nothin' 'bout no /usr/lib/cron/log. What is this file?
+ I don't see any reason to create log entries, given the mail-the-
+ output behaviour. Opinions, anyone? >>
+
+I will come up with other ideas no doubt, but I can always implement them
+myself.
+
+<< That's what I like about PD software. Please send me the diffs! >>
+
+The other problem you have is making sure you can run standard
+crontabs. I would suggest something like this: if the command part of the
+entry starts with an unescaped -, then flags and options follow immediately
+thereafter. As in:
+
+2,12,22,32,42,52 * * * * -q /usr/lib/uucp/uudemon.hr
+
+This could mean do not log the uudemon.hr run unless there is a problem of
+some kind. This is probably safe as not many filenames start with "-", and
+those that do are already a problem for people.
+
+<< Since I don't plan on supporting /usr/lib/cron/log in ANY form unless
+ many people request it, I won't be needing -q as you've defined it.
+ I could use something like this to avoid sending mail on errors, for
+ the occasional script that you don't want to bullet-proof.
+
+ The compatibility issue is CRITICAL. The 4.3BSD crontab format is
+ a crime against the whole philosophy of Unix(TM), in my opinion. >>
+
+One other minor thing to consider is the ulimit: can different users get
+different ulimits for their crontab entries?
+
+<< Boy I'm ignorant today. What's a ulimit, and what should I do with
+ it in a crontab? Suggestions, enlightenment, etc ?? >>
+
+From qantel!lll-crg!ames!uw-beaver!uw-nsr!john Tue Jan 6 23:32:44 1987
+Date: Thu, 1 Jan 87 10:53:05 pst
+From: lll-crg!ames!uw-beaver!uw-nsr!john (John Sambrook 5-7433)
+To: vixie!paul
+Status: RO
+
+How about not hardwiring the default environment that cron builds for its
+children in the cron program itself? Our cron does this and it's the pits
+because we are TZ=PST8PDT not TZ=EST5EDT !
+
+<< yeachk. I assure you, I will not hardwire the TZ! >>
+From ptsfa!well!dv Fri Jan 9 04:01:50 1987
+Date: Thu, 8 Jan 87 23:50:40 pst
+From: well!dv (David W. Vezie)
+To: ptsfa!vixie!paul
+Status: RO
+
+6, have a special notation called 'H' which would expand to weekends
+ and holidays (you'd have to keep a database somewhere of real
+ holidays), and also 'W' for workdays (neither weekend or holiday).
+
+<< Too much work. There should be a standard way to define and
+ detect holidays under Unix(TM); if there were, I'd use it. As
+ it is, I'll leave this for someone else to add.
+
+ I can see the usefulness; it just doesn't quite seem worth it. >>
+From qantel!gatech!akgua!blnt1!jat Wed Jan 14 20:00:40 1987
+Date: Tue, 13 Jan 87 16:39:38 EST
+From: gatech!akgua!blnt1!jat
+Status: RO
+
+1) Add some way to tell cron to reread the files, say kill -1 <pid>
+
+<< whenever the 'crontab' program is run and updates a crontab file,
+ a file /usr/spool/cron/POKECRON is created; next time the cron
+ daemon wakes up, it sees it, and re-reads the crontab files.
+
+ I thought of handling the signal; even implemented it. Then this
+ clever idea hit me and I ripped it all out and added a single
+ IF-statement to handle the POKECRON file. >>
+
+2) Have some kind of retry time so that if a command fails, cron will try to
+ execute it again after a certain period. This is useful if you have some
+ type of cleanup program that can run at the scheduled time for some reason
+ (such as locked device, unmounted filesystem, etc).
+
+<< Hmmm, sounds useful. I could do this by submitting an 'at' job...
+ I'll think about it. >>
+From ptsfa!dual!ucbvax!ihnp4!mtuxo!ender Sat Jan 3 16:54:00 1987
+From: dual!ucbvax!ihnp4!mtuxo!ender
+Date: Sat, 3 Jan 87 14:05:13 PST
+To: ucbvax!dual!ptsfa!vixie!paul
+Status: RO
+
+It would be nice if nonprivileged users can setup personal crontab files
+(~/.cronrc, say) and be able to run personal jobs at regular intervals.
+
+<< this is done, but in the SysV style: the 'crontab' program installs
+ a new crontab file for the executing user (can be overridden by root
+ for setup of uucp and news). the advantage of this is that (1) when
+ a crontab is changed, the daemon can be informed automatically; and
+ (2) the file can be syntax-checked before installation. >>
+From ptsfa!ames!seismo!ihnp4!lcc!richard Fri Jan 16 04:47:33 1987
+Date: Fri, 16 Jan 87 07:44:57 EST
+To: nike!ptsfa!vixie!paul
+Status: RO
+
+The System V cron is nice, but it has a few annoying features. One is that
+its mail files will say that the previous message is the output of "one of your
+cron commands." I wish it would say WHICH cron commmand.
+
+<< Done. Also which shell, which user (useful when the mail gets
+ forwarded), which home directory, and other useful crud. >>
+
+Another problem is with timezones. It is necessary to specify TZ=PST8PDT (or
+whatever) when you invoke cron (from inittab, or /etc/rc) and it is also
+necessary to add TZ=PST8PDT to each crontab line which might need it. Cron
+should automatically export its idea of the "TZ" to each invoked command, and
+it should be possible to put a line in the crontab file which overrides that
+for every command in the file (e.g., most users are on EST, so cron is run
+with TZ=EST5EDT; but one user is usually on PST and wants all of his cron
+commands to run with TZ=PST8PDT). This might be extended to allow any
+environment variable to be specified once for the whole crontab file (e.g.,
+PATH).
+
+<< Well, since I run the user's shell, you could put this into .cshrc.
+ generic environment-variable setting could be useful, though. Since
+ I have to modify the environment anyway, I'll consider this. >>
+
+A log file might be a nice idea, but the System V cron log is too verbose.
+I seem to remember that cron keeps it open, too; so you can't even have
+something go and periodically clean it out.
+
+<< I don't do /usr/lib/cron/log. I wasn't aware of this file until I
+ got all these suggestions. Do people want this file? Tell me! >>
diff --git a/usr.sbin/cron/doc/Makefile.vixie b/usr.sbin/cron/doc/Makefile.vixie
new file mode 100644
index 0000000..3dab5ad
--- /dev/null
+++ b/usr.sbin/cron/doc/Makefile.vixie
@@ -0,0 +1,128 @@
+#/* 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
+# */
+
+# Makefile for vixie's cron
+#
+# $Id: Makefile,v 2.9 1994/01/15 20:43:43 vixie Exp $
+#
+# vix 03mar88 [moved to RCS, rest of log is in there]
+# vix 30mar87 [goodbye, time.c; hello, getopt]
+# vix 12feb87 [cleanup for distribution]
+# vix 30dec86 [written]
+
+# NOTES:
+# 'make' can be done by anyone
+# 'make install' must be done by root
+#
+# this package needs getopt(3), bitstring(3), and BSD install(8).
+#
+# the configurable stuff in this makefile consists of compilation
+# options (use -O, cron runs forever) and destination directories.
+# SHELL is for the 'augumented make' systems where 'make' imports
+# SHELL from the environment and then uses it to run its commands.
+# if your environment SHELL variable is /bin/csh, make goes real
+# slow and sometimes does the wrong thing.
+#
+# this package needs the 'bitstring macros' library, which is
+# available from me or from the comp.sources.unix archive. if you
+# put 'bitstring.h' in a non-standard place (i.e., not intuited by
+# cc(1)), you will have to define INCLUDE to set the include
+# directory for cc. INCLUDE should be `-Isomethingorother'.
+#
+# there's more configuration info in config.h; edit that first!
+
+#################################### begin configurable stuff
+#<<DESTROOT is assumed to have ./etc, ./bin, and ./man subdirectories>>
+DESTROOT = $(DESTDIR)/usr
+DESTSBIN = $(DESTROOT)/sbin
+DESTBIN = $(DESTROOT)/bin
+DESTMAN = $(DESTROOT)/share/man
+#<<need bitstring.h>>
+INCLUDE = -I.
+#INCLUDE =
+#<<need getopt()>>
+LIBS =
+#<<optimize or debug?>>
+#OPTIM = -O
+OPTIM = -g
+#<<ATT or BSD or POSIX?>>
+# (ATT untested)
+#COMPAT = -DATT
+#(BSD is only needed if <sys/params.h> does not define it, as on ULTRIX)
+#COMPAT = -DBSD
+# (POSIX)
+#COMPAT = -DPOSIX
+#<<lint flags of choice?>>
+LINTFLAGS = -hbxa $(INCLUDE) $(COMPAT) $(DEBUGGING)
+#<<want to use a nonstandard CC?>>
+#CC = vcc
+#<<manifest defines>>
+DEFS =
+#(SGI IRIX systems need this)
+#DEFS = -D_BSD_SIGNALS -Dconst=
+#<<the name of the BSD-like install program>>
+#INSTALL = installbsd
+INSTALL = install
+#<<any special load flags>>
+LDFLAGS =
+#################################### end configurable stuff
+
+SHELL = /bin/sh
+CFLAGS = $(OPTIM) $(INCLUDE) $(COMPAT) $(DEFS)
+
+INFOS = README CHANGES FEATURES INSTALL CONVERSION THANKS MAIL
+MANPAGES = bitstring.3 crontab.5 crontab.1 cron.8 putman.sh
+HEADERS = bitstring.h cron.h config.h pathnames.h \
+ externs.h compat.h
+SOURCES = cron.c crontab.c database.c do_command.c entry.c \
+ env.c job.c user.c popen.c misc.c compat.c
+SHAR_SOURCE = $(INFOS) $(MANPAGES) Makefile $(HEADERS) $(SOURCES)
+LINT_CRON = cron.c database.c user.c entry.c compat.c \
+ misc.c job.c do_command.c env.c popen.c
+LINT_CRONTAB = crontab.c misc.c entry.c env.c compat.c
+CRON_OBJ = cron.o database.o user.o entry.o job.o do_command.o \
+ misc.o env.o popen.o compat.o
+CRONTAB_OBJ = crontab.o misc.o entry.o env.o compat.o
+
+all : cron crontab
+
+lint :
+ lint $(LINTFLAGS) $(LINT_CRON) $(LIBS) \
+ |grep -v "constant argument to NOT" 2>&1
+ lint $(LINTFLAGS) $(LINT_CRONTAB) $(LIBS) \
+ |grep -v "constant argument to NOT" 2>&1
+
+cron : $(CRON_OBJ)
+ $(CC) $(LDFLAGS) -o cron $(CRON_OBJ) $(LIBS)
+
+crontab : $(CRONTAB_OBJ)
+ $(CC) $(LDFLAGS) -o crontab $(CRONTAB_OBJ) $(LIBS)
+
+install : all
+ $(INSTALL) -c -m 111 -o root -s cron $(DESTSBIN)/
+ $(INSTALL) -c -m 4111 -o root -s crontab $(DESTBIN)/
+ sh putman.sh crontab.1 $(DESTMAN)
+ sh putman.sh cron.8 $(DESTMAN)
+ sh putman.sh crontab.5 $(DESTMAN)
+
+clean :; rm -f *.o cron crontab a.out core tags *~ #*
+
+kit : $(SHAR_SOURCE)
+ makekit -m -s99k $(SHAR_SOURCE)
+
+$(CRON_OBJ) : cron.h compat.h config.h externs.h pathnames.h Makefile
+$(CRONTAB_OBJ) : cron.h compat.h config.h externs.h pathnames.h Makefile
diff --git a/usr.sbin/cron/doc/README b/usr.sbin/cron/doc/README
new file mode 100644
index 0000000..751f04f
--- /dev/null
+++ b/usr.sbin/cron/doc/README
@@ -0,0 +1,72 @@
+#/* 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
+# */
+
+Vixie Cron V3.0
+December 27, 1993
+[V2.2 was some time in 1992]
+[V2.1 was May 29, 1991]
+[V2.0 was July 5, 1990]
+[V2.0-beta was December 9, 1988]
+[V1.0 was May 6, 1987]
+Paul Vixie
+
+This is a version of 'cron' that is known to run on BSD 4.[23] systems. It
+is functionally based on the SysV cron, which means that each user can have
+their own crontab file (all crontab files are stored in a read-protected
+directory, usually /var/cron/tabs). No direct support is provided for
+'at'; you can continue to run 'atrun' from the crontab as you have been
+doing. If you don't have atrun (i.e., System V) you are in trouble.
+
+A messages is logged each time a command is executed; also, the files
+"allow" and "deny" in /var/cron can be used to control access to the
+"crontab" command (which installs crontabs). It hasn't been tested on
+SysV, although some effort has gone into making the port an easy one.
+
+This is more or less the copyright that USENET contributed software usually
+has. Since ATT couldn't use this version if they had to freely distribute
+source, and since I'd love to see them use it, I'll offer some rediculously
+low license fee just to have them take it. In the unlikely event that they
+do this, I will continue to support and distribute the pseudo-PD version, so
+please, don't flame me for wanting my work to see a wider distribution.
+
+To use this: Sorry, folks, there is no cutesy 'Configure' script. You'll
+have to go edit a couple of files... So, here's the checklist:
+
+ Read all the FEATURES, INSTALL, and CONVERSION files
+ Edit config.h
+ Edit Makefile
+ (both of these files have instructions inside; note that
+ some things in config.h are definable in Makefile and are
+ therefore surrounded by #ifndef...#endif)
+ 'make'
+ 'su' and 'make install'
+ (you may have to install the man pages by hand)
+ kill your existing cron process
+ (actually you can run your existing cron if you want, but why?)
+ build new crontabs using /usr/lib/{crontab,crontab.local}
+ (either put them all in "root"'s crontab, or divide it up
+ and rip out all the 'su' commands, collapse the lengthy
+ lists into ranges with steps -- basically, this step is
+ as much work as you want to make it)
+ start up the new cron
+ (must be done as root)
+ watch it. test it with 'crontab -r' and watch the daemon track your
+ changes.
+ if you like it, change your /etc/{rc,rc.local} to use it instead of
+ the old one.
+
+$Id: README,v 2.3 1993/12/28 08:34:43 vixie Exp $
diff --git a/usr.sbin/cron/doc/README.1ST b/usr.sbin/cron/doc/README.1ST
new file mode 100644
index 0000000..66cd0b2
--- /dev/null
+++ b/usr.sbin/cron/doc/README.1ST
@@ -0,0 +1,4 @@
+Sources substantially rearranged 26 Aug 94, Jordan Hubbard. Content
+remains faithful to the original 3.0 cron source from Paul Vixie, but
+any bugs introduced by this reorganization or the port to FreeBSD remain
+purely my own. - Jordan
diff --git a/usr.sbin/cron/doc/THANKS b/usr.sbin/cron/doc/THANKS
new file mode 100644
index 0000000..3787c29
--- /dev/null
+++ b/usr.sbin/cron/doc/THANKS
@@ -0,0 +1,29 @@
+15 January 1990
+Paul Vixie
+
+Many people have contributed to cron. Many more than I can remember, in fact.
+Rich Salz and Carl Gutekunst were each of enormous help to me in V1; Carl for
+helping me understand UNIX well enough to write it, and Rich for helping me
+get the features right.
+
+John Gilmore wrote me a wonderful review of V2, which took me a whole year to
+answer even though it made me clean up some really awful things in the code.
+(According to John the most awful things are still in here, of course.)
+
+Paul Close made a suggestion which led to /etc/crond.pid and the mutex locking
+on it. Kevin Braunsdorf of Purdue made a suggestion that led to @reboot and
+its brothers and sisters; he also sent some diffs that lead cron toward compil-
+ability with System V, though without at(1) capabilities, this cron isn't going
+to be that useful on System V. Bob Alverson fixed a silly bug in the line
+number counting. Brian Reid made suggestions which led to the run queue and
+the source-file labelling in installed crontabs.
+
+Scott Narveson ported V2 to a Sequent, and sent in the most useful single batch
+of diffs I got from anybody. Changes attributable to Scott are:
+ -> sendmail won't time out if the command is slow to generate output
+ -> day-of-week names aren't off by one anymore
+ -> crontab says the right thing if you do something you shouldn't do
+ -> crontab(5) man page is longer and more informative
+ -> misc changes related to the side effects of fclose()
+ -> Sequent "universe" support added (may also help on Pyramids)
+ -> null pw_shell is dealt with now; default is /bin/sh
diff --git a/usr.sbin/cron/lib/Makefile b/usr.sbin/cron/lib/Makefile
new file mode 100644
index 0000000..ff76913
--- /dev/null
+++ b/usr.sbin/cron/lib/Makefile
@@ -0,0 +1,11 @@
+LIB= cron
+
+SRCS= entry.c env.c misc.c
+CFLAGS+= -I${.CURDIR}/../cron
+NOSHARED= yes
+NOPROFILE= yes
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/cron/lib/compat.c b/usr.sbin/cron/lib/compat.c
new file mode 100644
index 0000000..205c731
--- /dev/null
+++ b/usr.sbin/cron/lib/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.6 1994/01/15 20:43:43 vixie 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/lib/entry.c b/usr.sbin/cron/lib/entry.c
new file mode 100644
index 0000000..03273a3
--- /dev/null
+++ b/usr.sbin/cron/lib/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 2.12 1994/01/17 03:20:37 vixie 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/lib/env.c b/usr.sbin/cron/lib/env.c
new file mode 100644
index 0000000..535cb37
--- /dev/null
+++ b/usr.sbin/cron/lib/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 2.6 1994/01/15 20:43:43 vixie 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/lib/misc.c b/usr.sbin/cron/lib/misc.c
new file mode 100644
index 0000000..c912ffb
--- /dev/null
+++ b/usr.sbin/cron/lib/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 2.9 1994/01/15 20:43:43 vixie 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_SUIDS
+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/crunch/COPYRIGHT b/usr.sbin/crunch/COPYRIGHT
new file mode 100644
index 0000000..c7b4d2f
--- /dev/null
+++ b/usr.sbin/crunch/COPYRIGHT
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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 U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * 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.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
diff --git a/usr.sbin/crunch/Makefile b/usr.sbin/crunch/Makefile
new file mode 100644
index 0000000..a38e0b9
--- /dev/null
+++ b/usr.sbin/crunch/Makefile
@@ -0,0 +1,4 @@
+
+SUBDIR=crunchgen crunchide
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/crunch/Makefile.inc b/usr.sbin/crunch/Makefile.inc
new file mode 100644
index 0000000..da42105
--- /dev/null
+++ b/usr.sbin/crunch/Makefile.inc
@@ -0,0 +1,2 @@
+# modify to taste
+BINDIR?= /usr/bin
diff --git a/usr.sbin/crunch/README b/usr.sbin/crunch/README
new file mode 100644
index 0000000..27c2d02
--- /dev/null
+++ b/usr.sbin/crunch/README
@@ -0,0 +1,88 @@
+
+CRUNCH 0.2 README 6/14/94
+
+Crunch is available via anonymous ftp to ftp.cs.umd.edu in
+ pub/bsd/crunch-0.2.tar.gz
+
+
+WHAT'S NEW IN 0.2
+
+* The prototype awk script has been replaced by a more capable and
+ hopefully more robust C program.
+* No fragile template makefiles or dependencies on the details of the
+ bsd build environment.
+* You can build crunched binaries even with no sources on-line, you
+ just need the .o files. Crunchgen still will try to figure out as
+ much as possible on its own, but you can override its guessing by
+ specifying the list of .o files explicitly.
+* Crunch itself has been bmake'd and some man pages written, so it
+ should be ready to install.
+
+
+INTRODUCTION
+
+Crunch is a little package that helps create "crunched" binaries for use
+on boot, install, and fixit floppies. A crunched binary in this case is
+one where many programs have been linked together into one a.out file.
+The different programs are run depending on the value of argv[0], so
+hard links to the crunched binary suffice to simulate a perfectly normal
+system.
+
+As an example, I have created an 980K crunched "fixit" binary containing
+the following programs in their entirety:
+
+ cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+ mt mv pwd rcp rm rmdir sh sleep stty sync test [ badsect chown
+ clri disklabel dump rdump dmesg fdisk fsck halt ifconfig init
+ mknod mount newfs ping reboot restore rrestore swapon umount
+ ftp rsh sed telnet rlogin vi cpio gzip gunzip gzcat
+
+Note carefully: vi, cpio, gzip, ed, sed, dump/restore, some networking
+utilities, and the disk management utilities, all in a binary small
+enough to fit on a 1.2 MB root filesystem floppy (albeit with the kernel
+on its own boot floppy). A more reasonable subset can be made to fit
+easily with a kernel for a decent one-disk fixit filesystem.
+
+The linking together of different programs by hand is an old
+space-saving technique. Crunch automates the process by building the
+necessary stub files and makefile for you (via the crunchgen program),
+and by doctoring the symbol tables of the component .o files to allow
+them to link without "symbol multiply defined" conflicts (via the
+crunchide program).
+
+
+BUILDING CRUNCH
+
+Just type make, then make install.
+
+Crunch was written and tested under NetBSD/i386, but should work under
+other PC BSD systems that use GNU ld.
+
+The crunchgen(1) and crunchide(1) man pages have more details on using
+crunch, and the examples subdirectory contains some working .conf files
+and a sample Makefile.
+
+CREDITS
+
+Thanks to the NetBSD team for a consistently high quality effort in
+bringing together a solid, state of the art development environment.
+
+Thanks to the FreeBSD guys; Rod Grimes, Nate Williams and Jordan
+Hubbard; and to Bruce Evans, for immediate and detailed feedback on
+crunch 0.1, and for pressing me to make the prototype more useable.
+
+Crunch was written for the Maruti Hard Real-Time Operating System
+project at the University of Maryland, to help make for better install
+and recovery procedures for our NetBSD-based development environment. It
+is copyright (c) 1994 by the University of Maryland under a UCB-style
+freely- redistributable notice. See the file COPYRIGHT for details.
+
+Please let me know of any problems or of enhancements you make to this
+package. I'm particularly interested in the details of what you found
+was good to put on your fixit or install disks. Thanks!
+
+Share and Enjoy,
+Jaime
+............................................................................
+: Stand on my shoulders, : jds@cs.umd.edu : James da Silva
+: not on my toes. : uunet!mimsy!jds : http://www.cs.umd.edu/users/jds
diff --git a/usr.sbin/crunch/crunchgen/Makefile b/usr.sbin/crunch/crunchgen/Makefile
new file mode 100644
index 0000000..71acb21
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/Makefile
@@ -0,0 +1,9 @@
+
+PROG=crunchgen
+SRCS=crunchgen.c crunched_skel.c
+CFLAGS+=-g -Wall
+
+crunched_skel.c: crunched_main.c
+ ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c >crunched_skel.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/crunch/crunchgen/crunched_main.c b/usr.sbin/crunch/crunchgen/crunched_main.c
new file mode 100644
index 0000000..a07317a
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/crunched_main.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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 U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * 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.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunched_main.c - main program for crunched binaries, it branches to a
+ * particular subprogram based on the value of argv[0]. Also included
+ * is a little program invoked when the crunched binary is called via
+ * its EXECNAME. This one prints out the list of compiled-in binaries,
+ * or calls one of them based on argv[1]. This allows the testing of
+ * the crunched binary without creating all the links.
+ */
+#include <stdio.h>
+#include <string.h>
+
+struct stub {
+ char *name;
+ int (*f)();
+};
+
+extern struct stub entry_points[];
+
+int main(int argc, char **argv)
+{
+ char *slash, *basename;
+ struct stub *ep;
+
+ if(argv[0] == NULL || *argv[0] == '\0')
+ crunched_usage();
+
+ slash = strrchr(argv[0], '/');
+ basename = slash? slash+1 : argv[0];
+
+ for(ep=entry_points; ep->name != NULL; ep++)
+ if(!strcmp(basename, ep->name)) break;
+
+ if(ep->name)
+ return ep->f(argc, argv);
+ else {
+ fprintf(stderr, "%s: %s not compiled in\n", EXECNAME, basename);
+ crunched_usage();
+ }
+}
+
+
+int crunched_main(int argc, char **argv)
+{
+ struct stub *ep;
+ int columns, len;
+
+ if(argc <= 1)
+ crunched_usage();
+
+ return main(--argc, ++argv);
+}
+
+
+int crunched_usage()
+{
+ int columns, len;
+ struct stub *ep;
+
+ fprintf(stderr, "Usage: %s <prog> <args> ..., where <prog> is one of:\n",
+ EXECNAME);
+ columns = 0;
+ for(ep=entry_points; ep->name != NULL; ep++) {
+ len = strlen(ep->name) + 1;
+ if(columns+len < 80)
+ columns += len;
+ else {
+ fprintf(stderr, "\n");
+ columns = len;
+ }
+ fprintf(stderr, " %s", ep->name);
+ }
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+/* end of crunched_main.c */
+
diff --git a/usr.sbin/crunch/crunchgen/crunched_skel.c b/usr.sbin/crunch/crunchgen/crunched_skel.c
new file mode 100644
index 0000000..d605d6c
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/crunched_skel.c
@@ -0,0 +1,107 @@
+/* File created via mkskel.sh */
+
+char *crunched_skel[] = {
+ "/*",
+ " * Copyright (c) 1994 University of Maryland",
+ " * All Rights Reserved.",
+ " *",
+ " * 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 U.M. not be used in advertising or",
+ " * publicity pertaining to distribution of the software without specific,",
+ " * written prior permission. U.M. makes no representations about the",
+ " * suitability of this software for any purpose. It is provided \"as is\"",
+ " * without express or implied warranty.",
+ " *",
+ " * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL",
+ " * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.",
+ " * 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.",
+ " *",
+ " * Author: James da Silva, Systems Design and Analysis Group",
+ " * Computer Science Department",
+ " * University of Maryland at College Park",
+ " */",
+ "/*",
+ " * crunched_main.c - main program for crunched binaries, it branches to a ",
+ " * particular subprogram based on the value of argv[0]. Also included",
+ " * is a little program invoked when the crunched binary is called via",
+ " * its EXECNAME. This one prints out the list of compiled-in binaries,",
+ " * or calls one of them based on argv[1]. This allows the testing of",
+ " * the crunched binary without creating all the links.",
+ " */",
+ "#include <stdio.h>",
+ "#include <string.h>",
+ "",
+ "struct stub {",
+ " char *name;",
+ " int (*f)();",
+ "};",
+ "",
+ "extern struct stub entry_points[];",
+ "",
+ "int main(int argc, char **argv)",
+ "{",
+ " char *slash, *basename;",
+ " struct stub *ep;",
+ "",
+ " if(argv[0] == NULL || *argv[0] == '\\0')",
+ " crunched_usage();",
+ "",
+ " slash = strrchr(argv[0], '/');",
+ " basename = slash? slash+1 : argv[0];",
+ "",
+ " for(ep=entry_points; ep->name != NULL; ep++)",
+ " if(!strcmp(basename, ep->name)) break;",
+ "",
+ " if(ep->name)",
+ " return ep->f(argc, argv);",
+ " else {",
+ " fprintf(stderr, \"%s: %s not compiled in\\n\", EXECNAME, basename);",
+ " crunched_usage();",
+ " }",
+ "}",
+ "",
+ "",
+ "int crunched_main(int argc, char **argv)",
+ "{",
+ " struct stub *ep;",
+ " int columns, len;",
+ "",
+ " if(argc <= 1) ",
+ " crunched_usage();",
+ "",
+ " return main(--argc, ++argv);",
+ "}",
+ "",
+ "",
+ "int crunched_usage()",
+ "{",
+ " int columns, len;",
+ " struct stub *ep;",
+ "",
+ " fprintf(stderr, \"Usage: %s <prog> <args> ..., where <prog> is one of:\\n\",",
+ " EXECNAME);",
+ " columns = 0;",
+ " for(ep=entry_points; ep->name != NULL; ep++) {",
+ " len = strlen(ep->name) + 1;",
+ " if(columns+len < 80)",
+ " columns += len;",
+ " else {",
+ " fprintf(stderr, \"\\n\");",
+ " columns = len;",
+ " }",
+ " fprintf(stderr, \" %s\", ep->name);",
+ " }",
+ " fprintf(stderr, \"\\n\");",
+ " exit(1);",
+ "}",
+ "",
+ "/* end of crunched_main.c */",
+ "",
+ 0
+};
diff --git a/usr.sbin/crunch/crunchgen/crunchgen.1 b/usr.sbin/crunch/crunchgen/crunchgen.1
new file mode 100644
index 0000000..8c97d66
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/crunchgen.1
@@ -0,0 +1,266 @@
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" 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 U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" 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.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd June 14, 1994
+.Dt CRUNCHGEN 1
+.Os BSD 4
+.Sh NAME
+.Nm \&crunchgen
+.Nd generates build environment for a crunched binary
+.Sh SYNOPSIS
+.Nm \&crunchgen
+.Op Fl fq
+.Op Fl m Ar makefile-name
+.Op Fl c Ar c-file-name
+.Op Fl e Ar exec-file-name
+.Op Ar conf-file
+.Sh DESCRIPTION
+
+A crunched binary is a program made up of many other programs linked
+together into a single executable. The crunched binary main()
+function determines which component program to run by the contents of
+argv[0]. The main reason to crunch programs together is for fitting
+as many programs as possible onto an installation or system recovery
+floppy.
+
+.Pp
+.Nm Crunchgen
+reads in the specifications in
+.Ar conf-file
+for a crunched binary, and generates a Makefile and accompanying
+top-level C source file that when built create the crunched executable
+file from the component programs. For each component program,
+.Nm crunchgen
+can optionally attempt to determine the object (.o) files that make up
+the program from its source directory Makefile. This information is
+cached between runs.
+.Nm Crunchgen
+uses the companion program
+.Nm crunchide
+to eliminate link-time conflicts between the component programs by
+hiding all unnecessary symbols.
+
+.Pp
+After
+.Nm crunchgen
+is run, the crunched binary can be built by running ``make -f
+<conf-name>.mk''. The component programs' object files must already
+be built. A ``objs'' target, included in the output makefile, will
+run make in each component program's source dir to build the object
+files for the user. This is not done automatically since in release
+engineering circumstances it is generally not desireable to be
+modifying objects in other directories.
+
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl c Ar c-file-name
+Set output C file name to
+.Ar c-file-name .
+The default name is ``<conf-name>.c''.
+.It Fl e Ar exec-file-name
+Set crunched binary executable file name to
+.Ar exec-file-name .
+The default name is ``<conf-name>''.
+.It Fl f
+Flush cache. Forces the recalculation of cached parameters.
+.It Fl m Ar makefile-name
+Set output Makefile name to
+.Ar makefile-name .
+The default name is ``<conf-name>.mk''.
+.It Fl q
+Quiet operation. Status messages are suppressed.
+.El
+.Sh CRUNCHGEN CONFIGURATION FILE COMMANDS
+
+.Nm Crunchgen
+reads specifications from the
+.Ar conf-file
+that describe the components of the crunched binary. In its simplest
+use, the component program names are merely listed along with the
+top-level source directories in which their sources can be found.
+.Nm Crunchgen
+then calculates (via the source makefiles) and caches the
+list of object files and their locations. For more specialized
+situations, the user can specify by hand all the parameters that
+.Nm crunchgen
+needs.
+.Pp
+The
+.Ar conf-file
+commands are as follows:
+.Bl -tag -width indent
+.It Nm srcdirs Ar dirname ...
+A list of source trees in which the source directories of the
+component programs can be found. These dirs are searched using the
+BSD ``<source-dir>/<progname>/'' convention. Multiple
+.Nm srcdirs
+lines can be specified. The directories are searched in the order
+they are given.
+.It Nm progs Ar progname ...
+A list of programs that make up the crunched binary. Multiple
+.Nm progs
+lines can be specified.
+.It Nm libs Ar libspec ...
+A list of library specifications to be included in the crunched binary link.
+Multiple
+.Nm libs
+lines can be specified.
+.It Nm ln Ar progname linkname
+Causes the crunched binary to invoke
+.Ar progname
+whenever
+.Ar linkname
+appears in argv[0]. This allows programs that change their behavior when
+run under different names to operate correctly.
+.El
+
+To handle specialized situations, such as when the source is not
+available or not built via a conventional Makefile, the following
+.Nm special
+commands can be used to set
+.Nm crunchgen
+parameters for a component program.
+.Bl -tag -width indent
+.It Nm special Ar progname Nm srcdir Ar pathname
+Set the source directory for
+.Ar progname .
+This is normally calculated by searching the specified
+.Nm srcdirs
+for a directory named
+.Ar progname .
+.It Nm special Ar progname Nm objdir Ar pathname
+Set the obj directory for
+.Ar progname .
+This is normally calculated by looking for a directory named
+.Dq Pa obj
+under the
+.Ar srcdir ,
+and if that is not found, the
+.Ar srcdir
+itself becomes the
+.Ar objdir .
+.It Nm special Ar progname Nm objs Ar object-file-name ...
+Set the list of object files for program
+.Ar progname .
+This is normally calculated by constructing a temporary makefile that includes
+.Dq Nm srcdir / Pa Makefile
+and outputs the value of $(OBJS).
+.It Nm special Ar progname Nm objpaths Ar full-pathname-to-object-file ...
+Sets the pathnames of the object files for program
+.Ar progname .
+This is normally calculated by prepending the
+.Nm objdir
+pathname to each file in the
+.Nm objs
+list.
+.El
+
+.Pp
+Only the
+.Nm objpaths
+parameter is actually needed by
+.Nm crunchgen ,
+but it is calculated from
+.Nm objdir
+and
+.Nm objs ,
+which are in turn calculated from
+.Nm srcdir ,
+so is sometimes convenient to specify the earlier parameters and let
+.Nm crunchgen
+calculate forward from there if it can.
+
+.Pp
+The makefile produced by
+.Nm crunchgen
+contains an optional
+.Ar objs
+target that will build the object files for each component program by
+running make inside that program's source directory. For this to work the
+.Nm srcdir
+and
+.Nm objs
+parameters must also be valid. If they are not valid for a particular program, that
+program is skipped in the
+.Ar objs
+target.
+.Sh EXAMPLE
+Here is an example
+.Nm crunchgen
+input conf file, named
+.Dq Pa kcopy.conf :
+.Pp
+.nf
+ srcdirs /usr/src/bin /usr/src/sbin
+
+ progs test cp echo sh fsck halt init mount umount myinstall
+ ln test [ # test can be invoked via [
+ ln sh -sh # init invokes the shell with "-sh" in argv[0]
+
+ special myprog objpaths /homes/leroy/src/myinstall.o # no sources
+
+ libs -lutil -lcrypt
+.fi
+.Pp
+This conf file specifies a small crunched binary consisting of some
+basic system utilities plus a homegrown install program ``myinstall'',
+for which no source directory is specified, but its object file is
+specified directly with the
+.Nm special
+line.
+.Pp
+The crunched binary ``kcopy'' can be built as follows:
+.Pp
+.nf
+ % crunchgen -m Makefile kcopy.conf # gen Makefile and kcopy.c
+ % make objs # build the component progams' .o files
+ % make # build the crunched binary kcopy
+ % kcopy sh # test that this invokes a sh shell
+ $ # it works!
+.fi
+.Pp
+At this point the binary ``kcopy'' can be copied onto an install floppy
+and hard-linked to the names of the component programs.
+.Sh SEE ALSO
+.Xr crunchide 1
+.Sh CAVEATS
+While
+.Nm crunch
+takes care to eliminate link conflicts between the component programs
+of a crunched binary, conflicts are still possible between the
+libraries that are linked in. Some shuffling in the order of
+libraries may be required, and in some rare cases two libraries may
+have an unresolveable conflict and thus cannot be crunched together.
+.Pp
+Some versions of the BSD build environment do not by default build the
+intermediate object file for single-source file programs. The ``make
+objs'' target must then be used to get those object files built, or
+some other arrangements made.
+.Sh AUTHOR
+.Nm Crunch
+was written by James da Silva <jds@cs.umd.edu>.
+.sp 0
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
diff --git a/usr.sbin/crunch/crunchgen/crunchgen.c b/usr.sbin/crunch/crunchgen/crunchgen.c
new file mode 100644
index 0000000..6e9af18
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/crunchgen.c
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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 U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * 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.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * ========================================================================
+ * crunchgen.c
+ *
+ * Generates a Makefile and main C file for a crunched executable,
+ * from specs given in a .conf file.
+ */
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#define CRUNCH_VERSION "0.2"
+
+#define MAXLINELEN 16384
+#define MAXFIELDS 2048
+
+
+/* internal representation of conf file: */
+
+/* simple lists of strings suffice for most parms */
+
+typedef struct strlst {
+ struct strlst *next;
+ char *str;
+} strlst_t;
+
+/* progs have structure, each field can be set with "special" or calculated */
+
+typedef struct prog {
+ struct prog *next;
+ char *name, *ident;
+ char *srcdir, *objdir;
+ strlst_t *objs, *objpaths;
+ strlst_t *links;
+ int goterror;
+} prog_t;
+
+
+/* global state */
+
+strlst_t *srcdirs = NULL;
+strlst_t *libs = NULL;
+prog_t *progs = NULL;
+
+char line[MAXLINELEN];
+
+char confname[MAXPATHLEN], infilename[MAXPATHLEN];
+char outmkname[MAXPATHLEN], outcfname[MAXPATHLEN], execfname[MAXPATHLEN];
+char tempfname[MAXPATHLEN], cachename[MAXPATHLEN], curfilename[MAXPATHLEN];
+int linenum = -1;
+int goterror = 0;
+
+char *pname = "crunchgen";
+
+int verbose, readcache; /* options */
+int reading_cache;
+
+/* general library routines */
+
+void status(char *str);
+void out_of_memory(void);
+void add_string(strlst_t **listp, char *str);
+int is_dir(char *pathname);
+int is_nonempty_file(char *pathname);
+
+/* helper routines for main() */
+
+void usage(void);
+void parse_conf_file(void);
+void gen_outputs(void);
+
+
+int main(int argc, char **argv)
+{
+ char *p;
+ int optc;
+ extern int optind;
+ extern char *optarg;
+
+ verbose = 1;
+ readcache = 1;
+ *outmkname = *outcfname = *execfname = '\0';
+
+ if(argc > 0) pname = argv[0];
+
+ while((optc = getopt(argc, argv, "m:c:e:fq")) != -1) {
+ switch(optc) {
+ case 'f': readcache = 0; break;
+ case 'q': verbose = 0; break;
+
+ case 'm': strcpy(outmkname, optarg); break;
+ case 'c': strcpy(outcfname, optarg); break;
+ case 'e': strcpy(execfname, optarg); break;
+
+ case '?':
+ default: usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc != 1) usage();
+
+ /*
+ * generate filenames
+ */
+
+ strcpy(infilename, argv[0]);
+
+ /* confname = `basename infilename .conf` */
+
+ if((p=strrchr(infilename, '/')) != NULL) strcpy(confname, p+1);
+ else strcpy(confname, infilename);
+ if((p=strrchr(confname, '.')) != NULL && !strcmp(p, ".conf")) *p = '\0';
+
+ if(!*outmkname) sprintf(outmkname, "%s.mk", confname);
+ if(!*outcfname) sprintf(outcfname, "%s.c", confname);
+ if(!*execfname) sprintf(execfname, "%s", confname);
+
+ sprintf(cachename, "%s.cache", confname);
+ sprintf(tempfname, ".tmp_%sXXXXXX", confname);
+ if(mktemp(tempfname) == NULL) {
+ perror(tempfname);
+ exit(1);
+ }
+
+ parse_conf_file();
+ gen_outputs();
+
+ exit(goterror);
+}
+
+
+void usage(void)
+{
+ fprintf(stderr,
+ "%s [-fq] [-m <makefile>] [-c <c file>] [-e <exec file>] <conffile>\n",
+ pname);
+ exit(1);
+}
+
+
+/*
+ * ========================================================================
+ * parse_conf_file subsystem
+ *
+ */
+
+/* helper routines for parse_conf_file */
+
+void parse_one_file(char *filename);
+void parse_line(char *line, int *fc, char **fv, int nf);
+void add_srcdirs(int argc, char **argv);
+void add_progs(int argc, char **argv);
+void add_link(int argc, char **argv);
+void add_libs(int argc, char **argv);
+void add_special(int argc, char **argv);
+
+prog_t *find_prog(char *str);
+void add_prog(char *progname);
+
+
+void parse_conf_file(void)
+{
+ if(!is_nonempty_file(infilename)) {
+ fprintf(stderr, "%s: fatal: input file \"%s\" not found.\n",
+ pname, infilename);
+ exit(1);
+ }
+ parse_one_file(infilename);
+ if(readcache && is_nonempty_file(cachename)) {
+ reading_cache = 1;
+ parse_one_file(cachename);
+ }
+}
+
+
+void parse_one_file(char *filename)
+{
+ char *fieldv[MAXFIELDS];
+ int fieldc;
+ void (*f)(int c, char **v);
+ FILE *cf;
+
+ sprintf(line, "reading %s", filename);
+ status(line);
+ strcpy(curfilename, filename);
+
+ if((cf = fopen(curfilename, "r")) == NULL) {
+ perror(curfilename);
+ goterror = 1;
+ return;
+ }
+
+ linenum = 0;
+ while(fgets(line, MAXLINELEN, cf) != NULL) {
+ linenum++;
+ parse_line(line, &fieldc, fieldv, MAXFIELDS);
+ if(fieldc < 1) continue;
+ if(!strcmp(fieldv[0], "srcdirs")) f = add_srcdirs;
+ else if(!strcmp(fieldv[0], "progs")) f = add_progs;
+ else if(!strcmp(fieldv[0], "ln")) f = add_link;
+ else if(!strcmp(fieldv[0], "libs")) f = add_libs;
+ else if(!strcmp(fieldv[0], "special")) f = add_special;
+ else {
+ fprintf(stderr, "%s:%d: skipping unknown command `%s'.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ if(fieldc < 2) {
+ fprintf(stderr,
+ "%s:%d: %s command needs at least 1 argument, skipping.\n",
+ curfilename, linenum, fieldv[0]);
+ goterror = 1;
+ continue;
+ }
+ f(fieldc, fieldv);
+ }
+
+ if(ferror(cf)) {
+ perror(curfilename);
+ goterror = 1;
+ }
+ fclose(cf);
+}
+
+
+void parse_line(char *line, int *fc, char **fv, int nf)
+{
+ char *p;
+
+ p = line;
+ *fc = 0;
+ while(1) {
+ while(isspace(*p)) p++;
+ if(*p == '\0' || *p == '#') break;
+
+ if(*fc < nf) fv[(*fc)++] = p;
+ while(*p && !isspace(*p) && *p != '#') p++;
+ if(*p == '\0' || *p == '#') break;
+ *p++ = '\0';
+ }
+ if(*p) *p = '\0'; /* needed for '#' case */
+}
+
+
+void add_srcdirs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++) {
+ if(is_dir(argv[i]))
+ add_string(&srcdirs, argv[i]);
+ else {
+ fprintf(stderr, "%s:%d: `%s' is not a directory, skipping it.\n",
+ curfilename, linenum, argv[i]);
+ goterror = 1;
+ }
+ }
+}
+
+
+void add_progs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++)
+ add_prog(argv[i]);
+}
+
+
+void add_prog(char *progname)
+{
+ prog_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for(p1 = NULL, p2 = progs; p2 != NULL; p1 = p2, p2 = p2->next)
+ if(!strcmp(p2->name, progname)) return;
+
+ p2 = malloc(sizeof(prog_t));
+ if(p2) p2->name = strdup(progname);
+ if(!p2 || !p2->name)
+ out_of_memory();
+
+ p2->next = NULL;
+ if(p1 == NULL) progs = p2;
+ else p1->next = p2;
+
+ p2->ident = p2->srcdir = p2->objdir = NULL;
+ p2->links = p2->objs = NULL;
+ p2->goterror = 0;
+}
+
+
+void add_link(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if(p == NULL) {
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping link.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+ for(i=2;i<argc;i++)
+ add_string(&p->links, argv[i]);
+}
+
+
+void add_libs(int argc, char **argv)
+{
+ int i;
+
+ for(i=1;i<argc;i++)
+ add_string(&libs, argv[i]);
+}
+
+
+void add_special(int argc, char **argv)
+{
+ int i;
+ prog_t *p = find_prog(argv[1]);
+
+ if(p == NULL) {
+ if(reading_cache) return;
+ fprintf(stderr,
+ "%s:%d: no prog %s previously declared, skipping special.\n",
+ curfilename, linenum, argv[1]);
+ goterror = 1;
+ return;
+ }
+
+ if(!strcmp(argv[2], "ident")) {
+ if(argc != 4) goto argcount;
+ if((p->ident = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "srcdir")) {
+ if(argc != 4) goto argcount;
+ if((p->srcdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "objdir")) {
+ if(argc != 4) goto argcount;
+ if((p->objdir = strdup(argv[3])) == NULL)
+ out_of_memory();
+ }
+ else if(!strcmp(argv[2], "objs")) {
+ p->objs = NULL;
+ for(i=3;i<argc;i++)
+ add_string(&p->objs, argv[i]);
+ }
+ else if(!strcmp(argv[2], "objpaths")) {
+ p->objpaths = NULL;
+ for(i=3;i<argc;i++)
+ add_string(&p->objpaths, argv[i]);
+ }
+ else {
+ fprintf(stderr, "%s:%d: bad parameter name `%s', skipping line.\n",
+ curfilename, linenum, argv[2]);
+ goterror = 1;
+ }
+ return;
+
+
+ argcount:
+ fprintf(stderr,
+ "%s:%d: too %s arguments, expected \"special %s %s <string>\".\n",
+ curfilename, linenum, argc < 4? "few" : "many", argv[1], argv[2]);
+ goterror = 1;
+}
+
+
+prog_t *find_prog(char *str)
+{
+ prog_t *p;
+
+ for(p = progs; p != NULL; p = p->next)
+ if(!strcmp(p->name, str)) return p;
+
+ return NULL;
+}
+
+
+/*
+ * ========================================================================
+ * gen_outputs subsystem
+ *
+ */
+
+/* helper subroutines */
+
+void remove_error_progs(void);
+void fillin_program(prog_t *p);
+void gen_specials_cache(void);
+void gen_output_makefile(void);
+void gen_output_cfile(void);
+
+void fillin_program_objs(prog_t *p, char *path);
+void top_makefile_rules(FILE *outmk);
+void prog_makefile_rules(FILE *outmk, prog_t *p);
+void output_strlst(FILE *outf, strlst_t *lst);
+char *genident(char *str);
+char *dir_search(char *progname);
+
+
+void gen_outputs(void)
+{
+ prog_t *p;
+
+ for(p = progs; p != NULL; p = p->next)
+ fillin_program(p);
+
+ remove_error_progs();
+ gen_specials_cache();
+ gen_output_cfile();
+ gen_output_makefile();
+ status("");
+ fprintf(stderr,
+ "Run \"make -f %s objs exe\" to build crunched binary.\n",
+ outmkname);
+}
+
+
+void fillin_program(prog_t *p)
+{
+ char path[MAXPATHLEN];
+ char *srcparent;
+ strlst_t *s;
+
+ sprintf(line, "filling in parms for %s", p->name);
+ status(line);
+
+ if(!p->ident)
+ p->ident = genident(p->name);
+ if(!p->srcdir) {
+ srcparent = dir_search(p->name);
+ if(srcparent)
+ sprintf(path, "%s/%s", srcparent, p->name);
+ if(is_dir(path))
+ p->srcdir = strdup(path);
+ }
+ if(!p->objdir && p->srcdir) {
+ sprintf(path, "%s/obj", p->srcdir);
+ if(is_dir(path))
+ p->objdir = strdup(path);
+ else
+ p->objdir = p->srcdir;
+ }
+
+ if(p->srcdir) sprintf(path, "%s/Makefile", p->srcdir);
+ if(!p->objs && p->srcdir && is_nonempty_file(path))
+ fillin_program_objs(p, path);
+
+ if(!p->objpaths && p->objdir && p->objs)
+ for(s = p->objs; s != NULL; s = s->next) {
+ sprintf(line, "%s/%s", p->objdir, s->str);
+ add_string(&p->objpaths, line);
+ }
+
+ if(!p->srcdir && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find source directory.\n",
+ infilename, p->name);
+ if(!p->objs && verbose)
+ fprintf(stderr, "%s: %s: warning: could not find any .o files.\n",
+ infilename, p->name);
+
+ if(!p->objpaths) {
+ fprintf(stderr,
+ "%s: %s: error: no objpaths specified or calculated.\n",
+ infilename, p->name);
+ p->goterror = goterror = 1;
+ }
+}
+
+void fillin_program_objs(prog_t *p, char *path)
+{
+ char *obj, *cp;
+ int rc;
+ FILE *f;
+
+ /* discover the objs from the srcdir Makefile */
+
+ if((f = fopen(tempfname, "w")) == NULL) {
+ perror(tempfname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(f, ".include \"%s\"\n", path);
+ fprintf(f, ".if defined(PROG) && !defined(OBJS)\n");
+ fprintf(f, "OBJS=${PROG}.o\n");
+ fprintf(f, ".endif\n");
+ fprintf(f, "crunchgen_objs:\n\t@echo 'OBJS= '${OBJS}\n");
+ fclose(f);
+
+ sprintf(line, "make -f %s crunchgen_objs 2>&1", tempfname);
+ if((f = popen(line, "r")) == NULL) {
+ perror("submake pipe");
+ goterror = 1;
+ return;
+ }
+
+ while(fgets(line, MAXLINELEN, f)) {
+ if(strncmp(line, "OBJS= ", 6)) {
+ fprintf(stderr, "make error: %s", line);
+ goterror = 1;
+ continue;
+ }
+ cp = line + 6;
+ while(isspace(*cp)) cp++;
+ while(*cp) {
+ obj = cp;
+ while(*cp && !isspace(*cp)) cp++;
+ if(*cp) *cp++ = '\0';
+ add_string(&p->objs, obj);
+ while(isspace(*cp)) cp++;
+ }
+ }
+ if((rc=pclose(f)) != 0) {
+ fprintf(stderr, "make error: make returned %d\n", rc);
+ goterror = 1;
+ }
+ unlink(tempfname);
+}
+
+void remove_error_progs(void)
+{
+ prog_t *p1, *p2;
+
+ p1 = NULL; p2 = progs;
+ while(p2 != NULL) {
+ if(!p2->goterror)
+ p1 = p2, p2 = p2->next;
+ else {
+ /* delete it from linked list */
+ fprintf(stderr, "%s: %s: ignoring program because of errors.\n",
+ infilename, p2->name);
+ if(p1) p1->next = p2->next;
+ else progs = p2->next;
+ p2 = p2->next;
+ }
+ }
+}
+
+void gen_specials_cache(void)
+{
+ FILE *cachef;
+ prog_t *p;
+
+ sprintf(line, "generating %s", cachename);
+ status(line);
+
+ if((cachef = fopen(cachename, "w")) == NULL) {
+ perror(cachename);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(cachef, "# %s - parm cache generated from %s by crunchgen %s\n\n",
+ cachename, infilename, CRUNCH_VERSION);
+
+ for(p = progs; p != NULL; p = p->next) {
+ fprintf(cachef, "\n");
+ if(p->srcdir)
+ fprintf(cachef, "special %s srcdir %s\n", p->name, p->srcdir);
+ if(p->objdir)
+ fprintf(cachef, "special %s objdir %s\n", p->name, p->objdir);
+ if(p->objs) {
+ fprintf(cachef, "special %s objs", p->name);
+ output_strlst(cachef, p->objs);
+ }
+ fprintf(cachef, "special %s objpaths", p->name);
+ output_strlst(cachef, p->objpaths);
+ }
+ fclose(cachef);
+}
+
+
+void gen_output_makefile(void)
+{
+ prog_t *p;
+ FILE *outmk;
+
+ sprintf(line, "generating %s", outmkname);
+ status(line);
+
+ if((outmk = fopen(outmkname, "w")) == NULL) {
+ perror(outmkname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(outmk, "# %s - generated from %s by crunchgen %s\n\n",
+ outmkname, infilename, CRUNCH_VERSION);
+
+ top_makefile_rules(outmk);
+
+ for(p = progs; p != NULL; p = p->next)
+ prog_makefile_rules(outmk, p);
+
+ fprintf(outmk, "\n# ========\n");
+ fclose(outmk);
+}
+
+
+void gen_output_cfile(void)
+{
+ extern char *crunched_skel[];
+ char **cp;
+ FILE *outcf;
+ prog_t *p;
+ strlst_t *s;
+
+ sprintf(line, "generating %s", outcfname);
+ status(line);
+
+ if((outcf = fopen(outcfname, "w")) == NULL) {
+ perror(outcfname);
+ goterror = 1;
+ return;
+ }
+
+ fprintf(outcf,
+ "/* %s - generated from %s by crunchgen %s */\n",
+ outcfname, infilename, CRUNCH_VERSION);
+
+ fprintf(outcf, "#define EXECNAME \"%s\"\n", execfname);
+ for(cp = crunched_skel; *cp != NULL; cp++)
+ fprintf(outcf, "%s\n", *cp);
+
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outcf, "extern int _crunched_%s_stub();\n", p->ident);
+
+ fprintf(outcf, "\nstruct stub entry_points[] = {\n");
+ for(p = progs; p != NULL; p = p->next) {
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ p->name, p->ident);
+ for(s = p->links; s != NULL; s = s->next)
+ fprintf(outcf, "\t{ \"%s\", _crunched_%s_stub },\n",
+ s->str, p->ident);
+ }
+
+ fprintf(outcf, "\t{ EXECNAME, crunched_main },\n");
+ fprintf(outcf, "\t{ NULL, NULL }\n};\n");
+ fclose(outcf);
+}
+
+
+char *genident(char *str)
+{
+ char *n,*s,*d;
+
+ /*
+ * generates a Makefile/C identifier from a program name, mapping '-' to
+ * '_' and ignoring all other non-identifier characters. This leads to
+ * programs named "foo.bar" and "foobar" to map to the same identifier.
+ */
+
+ if((n = strdup(str)) == NULL)
+ return NULL;
+ for(d = s = n; *s != '\0'; s++) {
+ if(*s == '-') *d++ = '_';
+ else if(*s == '_' || isalnum(*s)) *d++ = *s;
+ }
+ *d = '\0';
+ return n;
+}
+
+
+char *dir_search(char *progname)
+{
+ char path[MAXPATHLEN];
+ strlst_t *dir;
+
+ for(dir=srcdirs; dir != NULL; dir=dir->next) {
+ sprintf(path, "%s/%s", dir->str, progname);
+ if(is_dir(path)) return dir->str;
+ }
+ return NULL;
+}
+
+
+void top_makefile_rules(FILE *outmk)
+{
+ prog_t *p;
+
+ fprintf(outmk, "LIBS=");
+ output_strlst(outmk, libs);
+
+ fprintf(outmk, "CRUNCHED_OBJS=");
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s.lo", p->name);
+ fprintf(outmk, "\n");
+
+ fprintf(outmk, "SUBMAKE_TARGETS=");
+ for(p = progs; p != NULL; p = p->next)
+ fprintf(outmk, " %s_make", p->ident);
+ fprintf(outmk, "\n\n");
+
+ fprintf(outmk, "%s: %s.o $(CRUNCHED_OBJS)\n",
+ execfname, execfname);
+ fprintf(outmk, "\t$(CC) -static -o %s %s.o $(CRUNCHED_OBJS) $(LIBS)\n",
+ execfname, execfname);
+ fprintf(outmk, "\tstrip %s\n", execfname);
+ fprintf(outmk, "all: objs exe\nobjs: $(SUBMAKE_TARGETS)\n");
+ fprintf(outmk, "exe: %s\n", execfname);
+ fprintf(outmk, "clean:\n\trm -f %s *.lo *.o *_stub.c\n",
+ execfname);
+}
+
+
+void prog_makefile_rules(FILE *outmk, prog_t *p)
+{
+ fprintf(outmk, "\n# -------- %s\n\n", p->name);
+
+ if(p->srcdir && p->objs) {
+ fprintf(outmk, "%s_SRCDIR=%s\n", p->ident, p->srcdir);
+ fprintf(outmk, "%s_OBJS=", p->ident);
+ output_strlst(outmk, p->objs);
+ fprintf(outmk, "%s_make:\n", p->ident);
+ fprintf(outmk, "\t(cd $(%s_SRCDIR); make $(%s_OBJS))\n\n",
+ p->ident, p->ident);
+ }
+ else
+ fprintf(outmk, "%s_make:\n\t@echo \"** cannot make objs for %s\"\n\n",
+ p->ident, p->name);
+
+ fprintf(outmk, "%s_OBJPATHS=", p->ident);
+ output_strlst(outmk, p->objpaths);
+
+ fprintf(outmk, "%s_stub.c:\n", p->name);
+ fprintf(outmk, "\techo \""
+ "int _crunched_%s_stub(int argc, char **argv, char **envp)"
+ "{return main(argc,argv,envp);}\" >%s_stub.c\n",
+ p->ident, p->name);
+ fprintf(outmk, "%s.lo: %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->name, p->ident);
+ fprintf(outmk, "\tld -dc -r -o %s.lo %s_stub.o $(%s_OBJPATHS)\n",
+ p->name, p->name, p->ident);
+ fprintf(outmk, "\tcrunchide -k __crunched_%s_stub %s.lo\n",
+ p->ident, p->name);
+}
+
+void output_strlst(FILE *outf, strlst_t *lst)
+{
+ for(; lst != NULL; lst = lst->next)
+ fprintf(outf, " %s", lst->str);
+ fprintf(outf, "\n");
+}
+
+
+/*
+ * ========================================================================
+ * general library routines
+ *
+ */
+
+void status(char *str)
+{
+ static int lastlen = 0;
+ int len, spaces;
+
+ if(!verbose) return;
+
+ len = strlen(str);
+ spaces = lastlen - len;
+ if(spaces < 1) spaces = 1;
+
+ fprintf(stderr, " [%s]%*.*s\r", str, spaces, spaces, " ");
+ fflush(stderr);
+ lastlen = len;
+}
+
+
+void out_of_memory(void)
+{
+ fprintf(stderr, "%s: %d: out of memory, stopping.\n", infilename, linenum);
+ exit(1);
+}
+
+
+void add_string(strlst_t **listp, char *str)
+{
+ strlst_t *p1, *p2;
+
+ /* add to end, but be smart about dups */
+
+ for(p1 = NULL, p2 = *listp; p2 != NULL; p1 = p2, p2 = p2->next)
+ if(!strcmp(p2->str, str)) return;
+
+ p2 = malloc(sizeof(strlst_t));
+ if(p2) p2->str = strdup(str);
+ if(!p2 || !p2->str)
+ out_of_memory();
+
+ p2->next = NULL;
+ if(p1 == NULL) *listp = p2;
+ else p1->next = p2;
+}
+
+
+int is_dir(char *pathname)
+{
+ struct stat buf;
+
+ if(stat(pathname, &buf) == -1)
+ return 0;
+ return S_ISDIR(buf.st_mode);
+}
+
+int is_nonempty_file(char *pathname)
+{
+ struct stat buf;
+
+ if(stat(pathname, &buf) == -1)
+ return 0;
+
+ return S_ISREG(buf.st_mode) && buf.st_size > 0;
+}
diff --git a/usr.sbin/crunch/crunchgen/mkskel.sh b/usr.sbin/crunch/crunchgen/mkskel.sh
new file mode 100644
index 0000000..fd53d78
--- /dev/null
+++ b/usr.sbin/crunch/crunchgen/mkskel.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+# idea and sed lines taken straight from flex
+
+cat <<!EOF
+/* File created via mkskel.sh */
+
+char *crunched_skel[] = {
+!EOF
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
+
+cat <<!EOF
+ 0
+};
+!EOF
diff --git a/usr.sbin/crunch/crunchide/Makefile b/usr.sbin/crunch/crunchide/Makefile
new file mode 100644
index 0000000..f6e1a8a
--- /dev/null
+++ b/usr.sbin/crunch/crunchide/Makefile
@@ -0,0 +1,4 @@
+
+PROG= crunchide
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/crunch/crunchide/crunchide.1 b/usr.sbin/crunch/crunchide/crunchide.1
new file mode 100644
index 0000000..38a04cf
--- /dev/null
+++ b/usr.sbin/crunch/crunchide/crunchide.1
@@ -0,0 +1,68 @@
+.\"
+.\" Copyright (c) 1994 University of Maryland
+.\" All Rights Reserved.
+.\"
+.\" 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 U.M. not be used in advertising or
+.\" publicity pertaining to distribution of the software without specific,
+.\" written prior permission. U.M. makes no representations about the
+.\" suitability of this software for any purpose. It is provided "as is"
+.\" without express or implied warranty.
+.\"
+.\" U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+.\" 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.
+.\"
+.\" Author: James da Silva, Systems Design and Analysis Group
+.\" Computer Science Department
+.\" University of Maryland at College Park
+.\"
+.Dd June 14, 1994
+.Dt CRUNCHIDE 1
+.Os BSD 4
+.Sh NAME
+.Nm crunchide
+.Nd hides symbol names from ld, for crunching programs together
+.Sh SYNOPSIS
+.Nm crunchide
+.Op Fl f Ar keep-list-file
+.Op Fl k Ar keep-symbol
+.Op Ar object-file ...
+.Sh DESCRIPTION
+
+.Nm Crunchide
+hides the global symbols of
+.Ar object-file
+such that they are ignored by subsequent runs of the linker,
+.Xr ld 1 .
+Some symbols may be left visible via the
+.Fl k Ar keep-symbol
+and
+.Fl f Ar keep-list-file
+options. The
+.Ar keep-list-file
+must contain a list of symbols to keep visible, one symbol per line.
+Note that the C compiler prepends an underscore in front of
+symbols, so to keep the C function ``foo'' visible, the option
+\&``-k _foo'' must be used.
+
+.Pp
+.Nm Crunchide
+is designed as a companion program for
+.Xr crunchgen 1 ,
+which automates the process of creating crunched binaries from
+multiple component programs.
+.Sh SEE ALSO
+.Xr crunchgen 1 ,
+.Xr ld 1
+.Sh AUTHOR
+.Nm Crunch
+was written by James da Silva <jds@cs.umd.edu>.
+.sp 0
+Copyright (c) 1994 University of Maryland. All Rights Reserved.
diff --git a/usr.sbin/crunch/crunchide/crunchide.c b/usr.sbin/crunch/crunchide/crunchide.c
new file mode 100644
index 0000000..ae54da0
--- /dev/null
+++ b/usr.sbin/crunch/crunchide/crunchide.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 1994 University of Maryland
+ * All Rights Reserved.
+ *
+ * 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 U.M. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. U.M. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
+ * 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.
+ *
+ * Author: James da Silva, Systems Design and Analysis Group
+ * Computer Science Department
+ * University of Maryland at College Park
+ */
+/*
+ * crunchide.c - tiptoes through an a.out symbol table, hiding all defined
+ * global symbols. Allows the user to supply a "keep list" of symbols
+ * that are not to be hidden. This program relies on the use of the
+ * linker's -dc flag to actually put global bss data into the file's
+ * bss segment (rather than leaving it as undefined "common" data).
+ *
+ * The point of all this is to allow multiple programs to be linked
+ * together without getting multiple-defined errors.
+ *
+ * For example, consider a program "foo.c". It can be linked with a
+ * small stub routine, called "foostub.c", eg:
+ * int foo_main(int argc, char **argv){ return main(argc, argv); }
+ * like so:
+ * cc -c foo.c foostub.c
+ * ld -dc -r foo.o foostub.o -o foo.combined.o
+ * crunchide -k _foo_main foo.combined.o
+ * at this point, foo.combined.o can be linked with another program
+ * and invoked with "foo_main(argc, argv)". foo's main() and any
+ * other globals are hidden and will not conflict with other symbols.
+ *
+ * TODO:
+ * - resolve the theoretical hanging reloc problem (see check_reloc()
+ * below). I have yet to see this problem actually occur in any real
+ * program. In what cases will gcc/gas generate code that needs a
+ * relative reloc from a global symbol, other than PIC? The
+ * solution is to not hide the symbol from the linker in this case,
+ * but to generate some random name for it so that it doesn't link
+ * with anything but holds the place for the reloc.
+ * - arrange that all the BSS segments start at the same address, so
+ * that the final crunched binary BSS size is the max of all the
+ * component programs' BSS sizes, rather than their sum.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+char *pname = "crunchide";
+
+void usage(void);
+
+void add_to_keep_list(char *symbol);
+void add_file_to_keep_list(char *filename);
+
+void hide_syms(char *filename);
+
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+ int ch;
+
+ if(argc > 0) pname = argv[0];
+
+ while ((ch = getopt(argc, argv, "k:f:")) != EOF)
+ switch(ch) {
+ case 'k':
+ add_to_keep_list(optarg);
+ break;
+ case 'f':
+ add_file_to_keep_list(optarg);
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc == 0) usage();
+
+ while(argc) {
+ hide_syms(*argv);
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+void usage(void)
+{
+ fprintf(stderr,
+ "Usage: %s [-k <symbol-name>] [-f <keep-list-file>] <files> ...\n",
+ pname);
+ exit(1);
+}
+
+/* ---------------------------- */
+
+struct keep {
+ struct keep *next;
+ char *sym;
+} *keep_list;
+
+void add_to_keep_list(char *symbol)
+{
+ struct keep *newp, *prevp, *curp;
+ int cmp;
+
+ for(curp = keep_list, prevp = NULL; curp; prevp = curp, curp = curp->next)
+ if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
+
+ if(curp && cmp == 0)
+ return; /* already in table */
+
+ newp = (struct keep *) malloc(sizeof(struct keep));
+ if(newp) newp->sym = strdup(symbol);
+ if(newp == NULL || newp->sym == NULL) {
+ fprintf(stderr, "%s: out of memory for keep list\n", pname);
+ exit(1);
+ }
+
+ newp->next = curp;
+ if(prevp) prevp->next = newp;
+ else keep_list = newp;
+}
+
+int in_keep_list(char *symbol)
+{
+ struct keep *curp;
+ int cmp;
+
+ for(curp = keep_list; curp; curp = curp->next)
+ if((cmp = strcmp(symbol, curp->sym)) <= 0) break;
+
+ return curp && cmp == 0;
+}
+
+void add_file_to_keep_list(char *filename)
+{
+ FILE *keepf;
+ char symbol[1024];
+ int len;
+
+ if((keepf = fopen(filename, "r")) == NULL) {
+ perror(filename);
+ usage();
+ }
+
+ while(fgets(symbol, 1024, keepf)) {
+ len = strlen(symbol);
+ if(len && symbol[len-1] == '\n')
+ symbol[len-1] = '\0';
+
+ add_to_keep_list(symbol);
+ }
+ fclose(keepf);
+}
+
+/* ---------------------- */
+
+int nsyms, ntextrel, ndatarel;
+struct exec *hdrp;
+char *aoutdata, *strbase;
+struct relocation_info *textrel, *datarel;
+struct nlist *symbase;
+
+
+#define SYMSTR(sp) &strbase[(sp)->n_un.n_strx]
+
+/* is the symbol a global symbol defined in the current file? */
+#define IS_GLOBAL_DEFINED(sp) \
+ (((sp)->n_type & N_EXT) && ((sp)->n_type & N_TYPE) != N_UNDF)
+
+/* is the relocation entry dependent on a symbol? */
+#define IS_SYMBOL_RELOC(rp) \
+ ((rp)->r_extern||(rp)->r_baserel||(rp)->r_jmptable)
+
+void check_reloc(char *filename, struct relocation_info *relp);
+
+void hide_syms(char *filename)
+{
+ int inf, outf, rc;
+ struct stat infstat;
+ struct relocation_info *relp;
+ struct nlist *symp;
+
+ /*
+ * Open the file and do some error checking.
+ */
+
+ if((inf = open(filename, O_RDWR)) == -1) {
+ perror(filename);
+ return;
+ }
+
+ if(fstat(inf, &infstat) == -1) {
+ perror(filename);
+ close(inf);
+ return;
+ }
+
+ if(infstat.st_size < sizeof(struct exec)) {
+ fprintf(stderr, "%s: short file\n", filename);
+ close(inf);
+ return;
+ }
+
+ /*
+ * Read the entire file into memory. XXX - Really, we only need to
+ * read the header and from TRELOFF to the end of the file.
+ */
+
+ if((aoutdata = (char *) malloc(infstat.st_size)) == NULL) {
+ fprintf(stderr, "%s: too big to read into memory\n", filename);
+ close(inf);
+ return;
+ }
+
+ if((rc = read(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
+ fprintf(stderr, "%s: read error: %s\n", filename,
+ rc == -1? strerror(errno) : "short read");
+ close(inf);
+ return;
+ }
+
+ /*
+ * Check the header and calculate offsets and sizes from it.
+ */
+
+ hdrp = (struct exec *) aoutdata;
+
+ if(N_BADMAG(*hdrp)) {
+ fprintf(stderr, "%s: bad magic: not an a.out file\n", filename);
+ close(inf);
+ return;
+ }
+
+#ifdef __FreeBSD__
+ textrel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp));
+ datarel = (struct relocation_info *) (aoutdata + N_RELOFF(*hdrp) +
+ hdrp->a_trsize);
+#else
+ textrel = (struct relocation_info *) (aoutdata + N_TRELOFF(*hdrp));
+ datarel = (struct relocation_info *) (aoutdata + N_DRELOFF(*hdrp));
+#endif
+ symbase = (struct nlist *) (aoutdata + N_SYMOFF(*hdrp));
+ strbase = (char *) (aoutdata + N_STROFF(*hdrp));
+
+ ntextrel = hdrp->a_trsize / sizeof(struct relocation_info);
+ ndatarel = hdrp->a_drsize / sizeof(struct relocation_info);
+ nsyms = hdrp->a_syms / sizeof(struct nlist);
+
+ /*
+ * Zap the type field of all globally-defined symbols. The linker will
+ * subsequently ignore these entries. Don't zap any symbols in the
+ * keep list.
+ */
+
+ for(symp = symbase; symp < symbase + nsyms; symp++)
+ if(IS_GLOBAL_DEFINED(symp) && !in_keep_list(SYMSTR(symp)))
+ symp->n_type = 0;
+
+ /*
+ * Check whether the relocation entries reference any symbols that we
+ * just zapped. I don't know whether ld can handle this case, but I
+ * haven't encountered it yet. These checks are here so that the program
+ * doesn't fail silently should such symbols be encountered.
+ */
+
+ for(relp = textrel; relp < textrel + ntextrel; relp++)
+ check_reloc(filename, relp);
+ for(relp = datarel; relp < datarel + ndatarel; relp++)
+ check_reloc(filename, relp);
+
+ /*
+ * Write the .o file back out to disk. XXX - Really, we only need to
+ * write the symbol table entries back out.
+ */
+ lseek(inf, 0, SEEK_SET);
+ if((rc = write(inf, aoutdata, infstat.st_size)) < infstat.st_size) {
+ fprintf(stderr, "%s: write error: %s\n", filename,
+ rc == -1? strerror(errno) : "short write");
+ }
+
+ close(inf);
+}
+
+
+void check_reloc(char *filename, struct relocation_info *relp)
+{
+ /* bail out if we zapped a symbol that is needed */
+ if(IS_SYMBOL_RELOC(relp) && symbase[relp->r_symbolnum].n_type == 0) {
+ fprintf(stderr,
+ "%s: oops, have hanging relocation for %s: bailing out!\n",
+ filename, SYMSTR(&symbase[relp->r_symbolnum]));
+ exit(1);
+ }
+}
diff --git a/usr.sbin/crunch/examples/Makefile b/usr.sbin/crunch/examples/Makefile
new file mode 100644
index 0000000..861e302
--- /dev/null
+++ b/usr.sbin/crunch/examples/Makefile
@@ -0,0 +1,32 @@
+
+CRUNCHED= fixit
+
+# below is boiler-plate to make $(CRUNCHED) from $(CRUNCHED).conf
+# I'd use PROG instead of CRUNCHED, but the system makefiles REALLY want
+# to build things in the normal way if you use PROG.
+
+CONF= $(CRUNCHED).conf
+
+OUTMK= $(CRUNCHED).mk
+OUTPUTS= $(OUTMK) $(CRUNCHED).c $(CRUNCHED).cache
+
+NOMAN=
+CLEANFILES+=$(CRUNCHED) *.o *.lo *.c *.mk *.cache
+CLEANDIRFILES+=$(OUTPUTS)
+
+all: $(CRUNCHED)
+exe: $(CRUNCHED)
+
+$(OUTPUTS): $(CONF)
+ crunchgen ${.CURDIR}/$(CONF)
+
+$(CRUNCHED): $(OUTPUTS) submake
+
+submake:
+ make -f $(OUTMK)
+objs:
+ make -f $(OUTMK) objs
+cleandir:
+ rm -f $(CLEANDIRFILES)
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/crunch/examples/filesystem.conf b/usr.sbin/crunch/examples/filesystem.conf
new file mode 100644
index 0000000..6ab43f0
--- /dev/null
+++ b/usr.sbin/crunch/examples/filesystem.conf
@@ -0,0 +1,30 @@
+# $Id: filesystem.conf,v 1.2 1994/06/24 16:39:29 jkh Exp $
+
+srcdirs /usr/src/bin /usr/src/sbin /usr/src/gnu/usr.bin /usr/src/usr.sbin
+
+# /bin
+progs sh expr ls mkdir rm sync test
+ln test [
+
+# These are needed because of UN*X's idiotic way of indicating that something
+# is a login shell.
+ln sh -
+ln sh -sh
+
+# /sbin
+progs disklabel fdisk init mount newfs reboot umount
+ln reboot halt
+ln reboot fastboot
+ln reboot fasthalt
+
+
+# /usr/bin
+progs cpio gzip
+ln gzip gunzip
+ln gzip gzcat
+ln gzip zcat
+
+# /usr/sbin
+progs bad144
+
+libs -ll -ledit -ltermcap -lcompat -lutil -lscrypt
diff --git a/usr.sbin/crunch/examples/fixit.conf b/usr.sbin/crunch/examples/fixit.conf
new file mode 100644
index 0000000..2298d41
--- /dev/null
+++ b/usr.sbin/crunch/examples/fixit.conf
@@ -0,0 +1,41 @@
+# fixit.conf - put in anything we think we might want on a fixit floppy
+
+# first, we list the source dirs that our programs reside in. These are
+# searched in order listed to find the dir containing each program.
+
+srcdirs /usr/src/bin /usr/src/sbin /usr/src/usr.bin /usr/src/usr.sbin
+srcdirs /usr/src/gnu/usr.bin
+
+# second, we list all the programs we want to include in our crunched binary.
+# The order doesn't matter. Any program that needs hard links to it gets an
+# `ln' directive.
+
+# /bin stuff
+
+progs cat chmod cp date dd df echo ed expr hostname kill ln ls mkdir
+progs mt mv pwd rcp rm rmdir sh sleep stty sync test
+
+ln test [
+ln sh -sh # init invokes the shell this way
+
+# /sbin stuff
+
+progs badsect chown clri disklabel dump dmesg fdisk fsck halt ifconfig init
+progs mknod mount newfs ping reboot restore swapon umount
+ln dump rdump
+ln restore rrestore
+
+# /usr/bin stuff
+
+progs ftp rsh sed telnet rlogin vi
+
+# gnu stuff
+
+progs cpio gzip
+ln gzip gunzip
+ln gzip gzcat
+
+# finally, we specify the libraries to link in with our binary
+
+libs -lcrypt -ltelnet -lutil -ll
+libs -lcurses -ltermcap
diff --git a/usr.sbin/crunch/examples/kcopy.conf b/usr.sbin/crunch/examples/kcopy.conf
new file mode 100644
index 0000000..5a3476d
--- /dev/null
+++ b/usr.sbin/crunch/examples/kcopy.conf
@@ -0,0 +1,21 @@
+# $Id: kcopy.conf,v 1.3 1994/06/24 16:39:30 jkh Exp $
+
+srcdirs /usr/src/bin /usr/src/sbin
+
+# Programs from bin/
+progs sh cp echo test
+ln test [
+
+# These are needed because of UN*X's idiotic way of indicating that something
+# is a login shell.
+ln sh -
+ln sh -sh
+
+#
+# Programs from sbin/
+progs mount mount_cd9660 fsck init reboot umount
+ln reboot halt
+ln reboot fastboot
+ln reboot fasthalt
+
+libs -ll -ledit -ltermcap -lcompat -lutil -lscrypt
diff --git a/usr.sbin/crunch/examples/really-big.conf b/usr.sbin/crunch/examples/really-big.conf
new file mode 100644
index 0000000..ce5083f
--- /dev/null
+++ b/usr.sbin/crunch/examples/really-big.conf
@@ -0,0 +1,146 @@
+# really-big.conf - just about everything, just for testing.
+# This ends up having some good examples of the use of specials for
+# those hard-to-reach programs. I stopped when I got tired, but we
+# could probably get even more stuff (like libexec stuff) in here.
+#
+# This produces a 4608000 byte binary. Pretty sick and twisted, eh?
+
+# =========================================================================
+
+srcdirs /usr/src/bin
+
+progs cat chmod cp csh date dd df domainname echo ed expr hostname kill
+progs ln ls mkdir mt mv ps pwd rcp rm rmail rmdir sh sleep stty sync test
+
+ln test [
+ln sh -sh
+
+
+# =========================================================================
+
+srcdirs /usr/src/sbin
+
+progs badsect bim clri disklabel dmesg dump dumpfs fdisk fsck halt
+progs ifconfig init mknod modload modunload mount mount_fdesc mount_isofs
+progs mount_kernfs mount_lofs mount_msdos mount_portal mount_procfs mountd
+progs newfs nfsd nfsiod ping quotacheck reboot restore route routed savecore
+progs shutdown slattach swapon ttyflags tunefs umount
+# shell scripts: fastboot
+
+ln dump rdump
+ln restore rrestore
+
+
+# =========================================================================
+
+srcdirs /usr/src/usr.bin
+
+progs apropos ar asa at basename biff cal calendar cap_mkdb checknr chpass
+progs cksum cmp col colcrt colrm column comm compress crontab ctags cut
+progs dirname du env error expand false file find finger fmt fold fpr from
+progs fsplit fstat ftp getconf getopt gprof head hexdump id indent ipcrm
+progs ipcs join kdump ktrace last lastcomm leave lex lock logger locate
+progs login logname look m4 machine mail make man mesg mkfifo
+progs mkstr modstat more msgs netstat newsyslog nfsstat nice nm nohup
+progs pagesize passwd paste patch pr printenv printf quota ranlib
+progs renice rev rlogin rpcgen rpcinfo rsh rup ruptime rusers rwall rwho
+progs script sed showmount size soelim split strings strip su tail talk
+progs tcopy tee telnet tftp time tip tn3270 touch tput tr true tset tsort
+progs tty ul uname unexpand unifdef uniq units unvis users uudecode uuencode
+progs vacation vgrind vi vis vmstat w wall wc what whatis whereis who
+progs whois window write xargs xinstall xstr yacc yes ypcat ypmatch ypwhich
+
+# shell scripts: lorder mkdep shar which
+# problems: rdist uses libcompat.a(regex.o), which conflicts with
+# libedit(readline.o) over regerror().
+
+# special requirements
+
+special locate srcdir /usr/src/usr.bin/locate/locate
+special tn3270 srcdir /usr/src/usr.bin/tn3270/tn3270
+
+
+# =========================================================================
+
+srcdirs /usr/src/usr.sbin
+
+progs ac accton amd arp bad144 catman chown chroot config config.new cron
+progs dev_mkdb diskpart edquota flcopy gettable grfinfo hilinfo htable inetd
+progs iostat iteconfig kvm_mkdb mrouted mtree named portmap pppd
+progs pstat pwd_mkdb quot quotaon rarpd rbootd repquota rmt rpc.bootparamd
+progs rwhod sa sliplogin slstats spray sysctl syslogd tcpdump
+progs traceroute trpt trsp update vipw vnconfig ypbind yppoll ypset
+
+special amd srcdir /usr/src/usr.sbin/amd/amd
+special amd objs vers.amd.o afs_ops.o am_ops.o clock.o util.o xutil.o efs_ops.o mapc.o info_file.o info_hes.o info_ndbm.o info_passwd.o info_nis.o info_union.o map.o srvr_afs.o srvr_nfs.o mntfs.o misc_rpc.o mount_fs.o mtab.o mtab_bsd.o nfs_ops.o nfs_prot_svc.o nfs_start.o nfs_subr.o opts.o pfs_ops.o rpc_fwd.o sched.o sfs_ops.o amq_svc.o amq_subr.o umount_fs.o host_ops.o nfsx_ops.o ufs_ops.o ifs_ops.o amd.o get_args.o restart.o wire.o
+
+
+srcdirs /usr/src/usr.sbin/lpr # lpr subsystem
+progs lpr lpc lpq lprm pac lptest
+special lpr srcdir /usr/src/usr.sbin/lpr/lpr
+
+srcdirs /usr/src/usr.sbin/sendmail # sendmail subsystem
+progs mailstats makemap praliases sendmail
+special sendmail srcdir /usr/src/usr.sbin/sendmail/src
+ln sendmail newaliases
+ln sendmail mailq
+
+srcdirs /usr/src/usr.sbin/timed # timed & timedc
+progs timed timedc
+special timed srcdir /usr/src/usr.sbin/timed/timed
+
+srcdirs /usr/src/usr.sbin/yp # yp subsystem
+progs ypbind ypwhich ypcat ypmatch ypset yppoll
+
+
+# =========================================================================
+
+srcdirs /usr/src/gnu/usr.bin
+
+progs bc cpio diff diff3 gas gawk grep gzip sdiff sort tar
+# shell scripts: send-pr
+
+srcdirs /usr/src/gnu/usr.bin/ld # ldd and ldconfig
+progs ld ldd ldconfig
+
+# rcs stuff loses because there are cross dependencies between librcs.a and
+# the individual programs. The solution would be to specify the objpaths
+# directly for each one, and include the full path to librcs.a each the
+# objpaths.
+
+# srcdirs /usr/src/gnu/usr.bin/rcs # rcs subsystem
+# progs ci co ident merge rcs rcsclean rcsdiff rcsmerge rlog
+# # shell script: rcsfreeze
+# special rcs srcdir /usr/src/gnu/usr.bin/rcs/rcs
+# libs /usr/src/gnu/usr.bin/rcs/lib/obj/librcs.a
+
+# gdb loses too
+# progs gdb
+# special gdb srcdir /usr/src/gnu/usr.bin/gdb/gdb
+# libs /usr/src/gnu/usr.bin/gdb/bfd/obj/libbfd.a
+# libs /usr/src/gnu/usr.bin/gdb/readline/obj/libreadline.a
+# libs /usr/src/gnu/usr.bin/gdb/libiberty/obj/libiberty.a
+
+# groff has the same problem as rcs
+# srcdirs /usr/src/gnu/usr.bin/groff # groff subsystem
+# progs groff troff tbl pic eqn grops grotty grodvi refer lookbib
+# progs indxbib lkbib tfmtodit addftinfo pfbtops psbb
+# shell script: nroff
+# special groff srcdir /usr/src/gnu/usr.bin/groff/groff
+# libs /usr/src/gnu/usr.bin/groff/libgroff/obj/libgroff.a
+# libs /usr/src/gnu/usr.bin/groff/libbib/obj/libbib.a
+# libs /usr/src/gnu/usr.bin/groff/libdriver/obj/libdriver.a
+
+srcdirs /usr/src/gnu/usr.bin/gcc2 # gcc & friends
+progs cc cpp cc1
+
+# cc1 has the same problem as rcs and groff, but since there's only one program
+# I'll go ahead and solve it as an example.
+
+special cc1 objpaths /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-parse.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-lang.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-lex.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-pragma.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-decl.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-typeck.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-convert.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-aux-info.o /usr/src/gnu/usr.bin/gcc2/cc1/obj/c-iterate.o /usr/src/gnu/usr.bin/gcc2/common/obj/libcc1.a
+
+ln gzip gunzip
+ln gzip gzcat
+
+libs -ledit -lgnumalloc -lc -lcrypt -ltermcap -lcurses -ltelnet -lutil -lkvm
+libs -ll -ly -lm -lresolv -lrpcsvc -lcompat
diff --git a/usr.sbin/ctm/Makefile b/usr.sbin/ctm/Makefile
new file mode 100644
index 0000000..dd9a766
--- /dev/null
+++ b/usr.sbin/ctm/Makefile
@@ -0,0 +1,4 @@
+
+SUBDIR= ctm ctm_scan
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/ctm/README b/usr.sbin/ctm/README
new file mode 100644
index 0000000..d887912
--- /dev/null
+++ b/usr.sbin/ctm/README
@@ -0,0 +1,97 @@
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+# $Id$
+#
+
+What will I not find in this file ?
+-----------------------------------
+Instructions on how to obtain FreeBSD via CTM.
+Contact <phk@freefall.cdrom.com> for that.
+
+What is CTM ?
+-------------
+CTM was originally "Cvs Through eMail", but has since changed scope to be
+much more general.
+CTM is now meant to be the definitive way to make and apply a delta between
+two versions of a directory tree.
+There are two parts to this, making the delta and applying it. These are two
+entirely different things. CTM concentrates the computation-burden on the
+generation og the deltas, as a delta very often is applied more times than
+it is made. Second CTM tries to make the minimal size delta.
+
+Why not use diff/patch ?
+------------------------
+Good question. Primarily because diff and patch doesn't do their job very
+well. They don't deal with binary files (in this case files with '\0' or
+'\0377' characters in them or files that doesn't end in '\n') which isn't
+a big surprise: they were made to deal with text-files only. As a second
+gripe, with patch you send the entire file to delete it. Not particular
+efficient.
+
+So what does CTM do exactly ?
+-----------------------------
+CTM will produce a file, (a delta) containing the instructions and data needed
+to take another copy of the tree from the old to the new status. CTM means to
+do this in the exact sense, and therefore the delta contains MD5 checksums to
+verify that the tree it is applied to is indeed in the state CTM expects.
+
+This means that if you have modified the tree locally, CTM might not be able
+to upgrade your copy.
+
+How do I make a CTM-delta ?
+---------------------------
+Don't. Send me email before you even try. This is yet not quite as trivial
+as I would like. This is not to discourage you from using CTM, it is merely
+to warn you that it is slightly tedious and takes much diskspace.
+
+How do I apply a CTM-delta ?
+----------------------------
+You pass it to the 'ctm' command. You can pass a CTM-delta on stdin, or
+you can give the filename as an argument. If you do the latter, you make
+life a lot easier for your self, since the program can accept gzip'ed files
+and since it will not have to make a temporary copy of your file. You can
+specify multiple deltas at one time, they will be proccessed one at a time.
+
+The ctm command runs in a number of passes. It will process the entire
+input file in each pass, before commencing with the next pass.
+
+Pass 1 will validate that the input file is OK. The syntax, the data and
+the global MD5 checksum will be checked. If any of these fail, ctm will
+never be able to do anything with the file, so it will simply reject it.
+
+Pass 2 will validate that the directory tree is in the state expected by
+the CTM-delta. This is done by looking for files and directories which
+should/should not exists and by checking the MD5 checksums of files.
+
+Pass 3 will actually apply the delta.
+
+Should I delete the delta when I have applied it ?
+--------------------------------------------------
+No. You might want to selectively reconstruct a file latter on.
+
+What features are are planned ?
+-------------------------------
+This list isn't exhaustive, and it isn't sorted in priority.
+ Reconstruct subset of tree.
+ Make tar-copy of things which will be affected.
+ Verify.
+ Internal editor instead of ed(1)
+ Support for mode
+ Support for uid/gid
+ Support for hardlinks
+ Support for symlinks
+
+Isn't this a bit thin yet ?
+---------------------------
+Yes.
+
+Can I say something ?
+---------------------
+Yes, email me: <phk@freefall.cdrom.com>
+
+Poul-Henning
diff --git a/usr.sbin/ctm/ctm/Makefile b/usr.sbin/ctm/ctm/Makefile
new file mode 100644
index 0000000..6906366
--- /dev/null
+++ b/usr.sbin/ctm/ctm/Makefile
@@ -0,0 +1,19 @@
+#
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+# $Id$
+#
+
+PROG= ctm
+NOTYET= ctm_ed.c
+SRCS= ctm.c ctm_input.c ctm_pass1.c ctm_pass2.c ctm_pass3.c \
+ ctm_syntax.c ctm_ed.c
+LDADD+= -lmd
+NOMAN= 1
+CFLAGS+= -Wall -g
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ctm/ctm/ctm.c b/usr.sbin/ctm/ctm/ctm.c
new file mode 100644
index 0000000..d4af9a6
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm.c
@@ -0,0 +1,199 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ * This is the client program of 'CTM'. It will apply a CTM-patch to a
+ * collection of files.
+ *
+ * Options we'd like to see:
+ *
+ * -a Attempt best effort.
+ * -b <dir> Base-dir
+ * -B <file> Backup to tar-file.
+ * -d <int> Debug TBD.
+ * -m <mail-addr> Email me instead.
+ * -r <name> Reconstruct file.
+ * -R <file> Read list of files to reconstruct.
+ *
+ * Options we have:
+ * -c Check it out, don't do anything.
+ * -F Force
+ * -p Less paranoid.
+ * -P Paranoid.
+ * -q Tell us less.
+ * -T <tmpdir>. Temporary files.
+ * -v Tell us more.
+ *
+ */
+
+#define EXTERN /* */
+#include "ctm.h"
+
+extern int Proc(char *);
+
+int
+main(int argc, char **argv)
+{
+ int stat=0;
+ int c;
+ extern int optopt,optind;
+ extern char * optarg;
+
+ Verbose = 1;
+ Paranoid = 1;
+ setbuf(stderr,0);
+ setbuf(stdout,0);
+
+ while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:Vv")) != -1) {
+ switch (c) {
+ case 'c': CheckIt++; break; /* Only check it */
+ case 'p': Paranoid--; break; /* Less Paranoid */
+ case 'P': Paranoid++; break; /* More Paranoid */
+ case 'q': Verbose--; break; /* Quiet */
+ case 'v': Verbose++; break; /* Verbose */
+ case 'T': TmpDir = optarg; break;
+ case 'F': Force = 1; break;
+ case ':':
+ fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
+ stat++;
+ break;
+ case '?':
+ fprintf(stderr,"Option '%c' not supported.\n",optopt);
+ stat++;
+ break;
+ default:
+ fprintf(stderr,"Option '%c' not yet implemented.\n",optopt);
+ break;
+ }
+ }
+
+ if(stat) {
+ fprintf(stderr,"%d errors during option processing\n",stat);
+ return Exit_Pilot;
+ }
+ stat = 0;
+ argc -= optind;
+ argv += optind;
+
+ if(!argc)
+ stat |= Proc("-");
+
+ while(argc-- && !stat) {
+ stat |= Proc(*argv++);
+ }
+
+ if(stat == Exit_Done)
+ stat = Exit_OK;
+
+ if(Verbose)
+ fprintf(stderr,"Exit(%d)\n",stat);
+ return stat;
+}
+
+int
+Proc(char *filename)
+{
+ FILE *f;
+ int i;
+ char *p = strrchr(filename,'.');
+
+ if(!strcmp(filename,"-")) {
+ p = 0;
+ f = stdin;
+ } else if(!strcmp(p,".gz") || !strcmp(p,".Z")) {
+ p = Malloc(100);
+ strcpy(p,"gunzip < ");
+ strcat(p,filename);
+ f = popen(p,"r");
+ if(!f) { perror(p); return Exit_Garbage; }
+ } else {
+ p = 0;
+ f = fopen(filename,"r");
+ }
+ if(!f) {
+ perror(filename);
+ return Exit_Garbage;
+ }
+
+ if(Verbose > 1)
+ fprintf(stderr,"Working on <%s>\n",filename);
+
+ if(FileName) Free(FileName);
+ FileName = String(filename);
+
+ /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
+ if(!p && -1 == fseek(f,0,SEEK_END)) {
+ char *fn = tempnam(TmpDir,"CMTclient");
+ FILE *f2 = fopen(fn,"w+");
+ int i;
+
+ if(!f2) {
+ perror(fn);
+ fclose(f);
+ return Exit_Broke;
+ }
+ unlink(fn);
+ fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
+ while(EOF != (i=getc(f)))
+ if(EOF == putc(i,f2)) {
+ fclose(f2);
+ return Exit_Broke;
+ }
+ fclose(f);
+ f = f2;
+ }
+
+ if(!p)
+ rewind(f);
+
+ if((i=Pass1(f)))
+ return i;
+
+ if(!p) {
+ rewind(f);
+ } else {
+ pclose(f);
+ f = popen(p,"r");
+ if(!f) { perror(p); return Exit_Broke; }
+ }
+
+ i=Pass2(f);
+
+ if(!p) {
+ rewind(f);
+ } else {
+ pclose(f);
+ f = popen(p,"r");
+ if(!f) { perror(p); return Exit_Broke; }
+ }
+
+ if(i) {
+ if((!Force) || (i & ~Exit_Forcible))
+ return i;
+ }
+
+ if(CheckIt) {
+ fprintf(stderr,"All checks out ok.\n");
+ return Exit_Done;
+ }
+
+ i=Pass3(f);
+
+ if(!p) {
+ fclose(f);
+ } else {
+ pclose(f);
+ Free(p);
+ }
+ if(i)
+ return i;
+
+ fprintf(stderr,"All done ok\n");
+ return Exit_Done;
+}
diff --git a/usr.sbin/ctm/ctm/ctm.h b/usr.sbin/ctm/ctm/ctm.h
new file mode 100644
index 0000000..93d1f9f
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm.h
@@ -0,0 +1,132 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <md5.h>
+#include <ctype.h>
+#include <string.h>
+#include <malloc.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#define VERSION "2.0"
+#define MAXSIZE (1024*1024*10)
+
+/* The fields... */
+#define CTM_F_MASK 0xff
+#define CTM_F_Name 0x01
+#define CTM_F_Uid 0x02
+#define CTM_F_Gid 0x03
+#define CTM_F_Mode 0x04
+#define CTM_F_MD5 0x05
+#define CTM_F_Count 0x06
+#define CTM_F_Bytes 0x07
+
+/* The qualifiers... */
+#define CTM_Q_MASK 0xff00
+#define CTM_Q_Name_File 0x0100
+#define CTM_Q_Name_Dir 0x0200
+#define CTM_Q_Name_New 0x0400
+#define CTM_Q_MD5_After 0x0100
+#define CTM_Q_MD5_Before 0x0200
+#define CTM_Q_MD5_Chunk 0x0400
+#define CTM_Q_MD5_Force 0x0800
+
+struct CTM_Syntax {
+ char *Key;
+ int *List;
+ };
+
+extern struct CTM_Syntax Syntax[];
+
+#define Malloc malloc
+#define Free free
+
+#ifndef EXTERN
+# define EXTERN extern
+#endif
+EXTERN u_char *Version;
+EXTERN u_char *Name;
+EXTERN u_char *Nbr;
+EXTERN u_char *TimeStamp;
+EXTERN u_char *Prefix;
+EXTERN u_char *FileName;
+EXTERN u_char *BaseDir;
+EXTERN u_char *TmpDir;
+
+/*
+ * Paranoid -- Just in case they should be after us...
+ * 0 not at all.
+ * 1 normal.
+ * 2 somewhat.
+ * 3 you bet!.
+ *
+ * Verbose -- What to tell mom...
+ * 0 Nothing which wouldn't surprise.
+ * 1 Normal.
+ * 2 Show progress '.'.
+ * 3 Show progress names, and actions.
+ * 4 even more...
+ * and so on
+ *
+ * ExitCode -- our Epitaph
+ * 0 Perfect, all input digested, no problems
+ * 1 Bad input, no point in retrying.
+ * 2 Pilot error, commandline problem &c
+ * 4 Out of resources.
+ * 8 Destination-tree not correct.
+ * 16 Destination-tree not correct, can force.
+ * 32 Internal problems.
+ *
+ */
+
+EXTERN int Paranoid;
+EXTERN int Verbose;
+EXTERN int Exit;
+EXTERN int Force;
+EXTERN int CheckIt;
+
+#define Exit_OK 0
+#define Exit_Garbage 1
+#define Exit_Pilot 2
+#define Exit_Broke 4
+#define Exit_NotOK 8
+#define Exit_Forcible 16
+#define Exit_Mess 32
+#define Exit_Done 64
+
+char * String(char *s);
+void Fatal_(int ln, char *fn, char *kind);
+#define Fatal(foo) Fatal_(__LINE__,__FILE__,foo)
+#define Assert() Fatal_(__LINE__,__FILE__,"Assert failed.")
+#define WRONG {Assert(); return Exit_Mess;}
+
+u_char * Ffield(FILE *fd, MD5_CTX *ctx,u_char term);
+
+int Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term);
+
+u_char * Fdata(FILE *fd, int u_chars, MD5_CTX *ctx);
+
+#define GETFIELD(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD
+#define GETFIELDCOPY(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD; else p=String(p)
+#define GETBYTECNT(p,q) if(0 >((p)= Fbytecnt(fd,&ctx,(q)))) return BADREAD
+#define GETDATA(p,q) if(!((p) = Fdata(fd,(q),&ctx))) return BADREAD
+
+int Pass1(FILE *fd);
+int Pass2(FILE *fd);
+int Pass3(FILE *fd);
+
+int ctm_edit(u_char *script, int length, char *filein, char *fileout);
diff --git a/usr.sbin/ctm/ctm/ctm_ed.c b/usr.sbin/ctm/ctm/ctm_ed.c
new file mode 100644
index 0000000..219fafc
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_ed.c
@@ -0,0 +1,103 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+
+int
+ctm_edit(u_char *script, int length, char *filein, char *fileout)
+{
+ u_char *ep, cmd;
+ int ln, ln2, iln, ret=0, c;
+ FILE *fi=0,*fo=0;
+
+ fi = fopen(filein,"r");
+ if(!fi) {
+ perror(filein);
+ return 8;
+ }
+
+ fo = fopen(fileout,"w");
+ if(!fo) {
+ perror(fileout);
+ fclose(fi);
+ return 4;
+ }
+ iln = 1;
+ for(ep=script;ep < script+length;) {
+ cmd = *ep++;
+ if(cmd != 'a' && cmd != 'd') { ret = 1; goto bye; }
+ ln = 0;
+ while(isdigit(*ep)) {
+ ln *= 10;
+ ln += (*ep++ - '0');
+ }
+ if(*ep++ != ' ') { ret = 1; goto bye; }
+ ln2 = 0;
+ while(isdigit(*ep)) {
+ ln2 *= 10;
+ ln2 += (*ep++ - '0');
+ }
+ if(*ep++ != '\n') { ret = 1; goto bye; }
+
+
+ if(cmd == 'd') {
+ while(iln < ln) {
+ c = getc(fi);
+ if(c == EOF) { ret = 1; goto bye; }
+ putc(c,fo);
+ if(c == '\n')
+ iln++;
+ }
+ while(ln2) {
+ c = getc(fi);
+ if(c == EOF) { ret = 1; goto bye; }
+ if(c != '\n')
+ continue;
+ ln2--;
+ iln++;
+ }
+ continue;
+ }
+ if(cmd == 'a') {
+ while(iln <= ln) {
+ c = getc(fi);
+ if(c == EOF) { ret = 1; goto bye; }
+ putc(c,fo);
+ if(c == '\n')
+ iln++;
+ }
+ while(ln2) {
+ c = *ep++;
+ putc(c,fo);
+ if(c != '\n')
+ continue;
+ ln2--;
+ }
+ continue;
+ }
+ ret = 1;
+ goto bye;
+ }
+ while(1) {
+ c = getc(fi);
+ if(c == EOF) break;
+ putc(c,fo);
+ }
+ fclose(fi);
+ fclose(fo);
+ return 0;
+bye:
+ if(fi) fclose(fi);
+ if(fo) fclose(fo);
+ return ret;
+}
+
diff --git a/usr.sbin/ctm/ctm/ctm_input.c b/usr.sbin/ctm/ctm/ctm_input.c
new file mode 100644
index 0000000..582bdf7
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_input.c
@@ -0,0 +1,113 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+
+/*---------------------------------------------------------------------------*/
+char *
+String(char *s)
+{
+ char *p = malloc(strlen(s) + 1);
+ strcpy(p,s);
+ return p;
+}
+/*---------------------------------------------------------------------------*/
+void
+Fatal_(int ln, char *fn, char *kind)
+{
+ if(Verbose > 2)
+ fprintf(stderr,"Fatal error. (%s:%d)\n",fn,ln);
+ fprintf(stderr,"%s Fatal error: %s\n",FileName, kind);
+}
+#define Fatal(foo) Fatal_(__LINE__,__FILE__,foo)
+#define Assert() Fatal_(__LINE__,__FILE__,"Assert failed.")
+
+/*---------------------------------------------------------------------------*/
+/* get next field, check that the terminating whitespace is what we expect */
+u_char *
+Ffield(FILE *fd, MD5_CTX *ctx,u_char term)
+{
+ static u_char buf[BUFSIZ];
+ int i,l;
+
+ for(l=0;;) {
+ if((i=getc(fd)) == EOF) {
+ Fatal("Truncated patch.");
+ return 0;
+ }
+ buf[l++] = i;
+ if(isspace(i))
+ break;
+ if(l >= sizeof buf) {
+ Fatal("Corrupt patch.");
+ printf("Token is too long.\n");
+ return 0;
+ }
+ }
+ buf[l] = '\0';
+ MD5Update(ctx,buf,l);
+ if(buf[l-1] != term) {
+ Fatal("Corrupt patch.");
+ fprintf(stderr,"Expected \"%s\" but didn't find it {%02x}.\n",
+ term == '\n' ? "\\n" : " ",buf[l-1]);
+ if(Verbose > 4)
+ fprintf(stderr,"{%s}\n",buf);
+ return 0;
+ }
+ buf[--l] = '\0';
+ if(Verbose > 4)
+ fprintf(stderr,"<%s>\n",buf);
+ return buf;
+}
+
+int
+Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term)
+{
+ u_char *p,*q;
+ int u_chars=0;
+
+ p = Ffield(fd,ctx,term);
+ if(!p) return -1;
+ for(q=p;*q;q++) {
+ if(!isdigit(*q)) {
+ Fatal("Bytecount contains non-digit.");
+ return -1;
+ }
+ u_chars *= 10;
+ u_chars += (*q - '0');
+ }
+ if(u_chars > MAXSIZE) {
+ Fatal("Bytecount too large.");
+ return -1;
+ }
+ return u_chars;
+}
+
+u_char *
+Fdata(FILE *fd, int u_chars, MD5_CTX *ctx)
+{
+ u_char *p = Malloc(u_chars+1);
+
+ if(u_chars+1 != fread(p,1,u_chars+1,fd)) {
+ Fatal("Truncated patch.");
+ return 0;
+ }
+ MD5Update(ctx,p,u_chars+1);
+ if(p[u_chars] != '\n') {
+ if(Verbose > 3)
+ printf("FileData wasn't followed by a newline.\n");
+ Fatal("Corrupt patch.");
+ return 0;
+ }
+ p[u_chars] = '\0';
+ return p;
+}
diff --git a/usr.sbin/ctm/ctm/ctm_pass1.c b/usr.sbin/ctm/ctm/ctm_pass1.c
new file mode 100644
index 0000000..a1ffaf6
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_pass1.c
@@ -0,0 +1,182 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+#define BADREAD 1
+
+/*---------------------------------------------------------------------------*/
+/* Pass1 -- Validate the incomming CTM-file.
+ */
+
+int
+Pass1(FILE *fd)
+{
+ u_char *p,*q;
+ MD5_CTX ctx;
+ int i,j,sep,cnt;
+ u_char *md5=0,*trash=0;
+ struct CTM_Syntax *sp;
+ int slashwarn=0;
+
+ if(Verbose>3)
+ printf("Pass1 -- Checking integrity of incomming CTM-patch\n");
+ MD5Init (&ctx);
+
+ GETFIELD(p,' '); /* CTM_BEGIN */
+ if(strcmp(p,"CTM_BEGIN")) {
+ Fatal("Probably not a CTM-patch at all.");
+ if(Verbose>3)
+ fprintf(stderr,"Expected \"CTM_BEGIN\" got \"%s\".\n",p);
+ return 1;
+ }
+
+ GETFIELDCOPY(Version,' '); /* <Version> */
+ if(strcmp(Version,VERSION)) {
+ Fatal("CTM-patch is wrong version.");
+ if(Verbose>3)
+ fprintf(stderr,"Expected \"%s\" got \"%s\".\n",VERSION,p);
+ return 1;
+ }
+
+ GETFIELDCOPY(Name,' '); /* <Name> */
+ GETFIELDCOPY(Nbr,' '); /* <Nbr> */
+ GETFIELDCOPY(TimeStamp,' '); /* <TimeStamp> */
+ GETFIELDCOPY(Prefix,'\n'); /* <Prefix> */
+
+ for(;;) {
+ if(md5) {Free(md5), md5 = 0;}
+ if(trash) {Free(trash), trash = 0;}
+ cnt = -1;
+
+ GETFIELD(p,' '); /* CTM_something */
+
+ if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') {
+ Fatal("Expected CTM keyword.");
+ fprintf(stderr,"Got [%s]\n",p);
+ return 1;
+ }
+
+ if(!strcmp(p+3,"_END"))
+ break;
+
+ for(sp=Syntax;sp->Key;sp++)
+ if(!strcmp(p+3,sp->Key))
+ goto found;
+ Fatal("Expected CTM keyword.");
+ fprintf(stderr,"Got [%s]\n",p);
+ return 1;
+ found:
+ if(Verbose > 5)
+ fprintf(stderr,"%s ",sp->Key);
+ for(i=0;(j = sp->List[i]);i++) {
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ sep = ' ';
+ else
+ sep = '\n';
+ if(Verbose > 5)
+ fprintf(stderr," %x(%d)",sp->List[i],sep);
+
+ switch (j & CTM_F_MASK) {
+ case CTM_F_Name: /* XXX check for garbage and .. */
+ GETFIELD(p,sep);
+ j = strlen(p);
+ if(p[j-1] == '/' && !slashwarn) {
+ fprintf(stderr,"Warning: contains trailing slash\n");
+ slashwarn++;
+ }
+ break;
+ case CTM_F_Uid:
+ GETFIELD(p,sep);
+ while(*p) {
+ if(!isdigit(*p)) {
+ Fatal("Non-digit in uid.");
+ return 32;
+ }
+ p++;
+ }
+ break;
+ case CTM_F_Gid:
+ GETFIELD(p,sep);
+ while(*p) {
+ if(!isdigit(*p)) {
+ Fatal("Non-digit in gid.");
+ return 32;
+ }
+ p++;
+ }
+ break;
+ case CTM_F_Mode:
+ GETFIELD(p,sep);
+ while(*p) {
+ if(!isdigit(*p)) {
+ Fatal("Non-digit in mode.");
+ return 32;
+ }
+ p++;
+ }
+ break;
+ case CTM_F_MD5:
+ if(j & CTM_Q_MD5_Chunk) {
+ GETFIELDCOPY(md5,sep); /* XXX check for garbage */
+ } else if(j & CTM_Q_MD5_Before) {
+ GETFIELD(p,sep); /* XXX check for garbage */
+ } else if(j & CTM_Q_MD5_After) {
+ GETFIELD(p,sep); /* XXX check for garbage */
+ } else {
+ fprintf(stderr,"List = 0x%x\n",j);
+ Fatal("Unqualified MD5.");
+ return 32;
+ }
+ break;
+ case CTM_F_Count:
+ GETBYTECNT(cnt,sep);
+ break;
+ case CTM_F_Bytes:
+ if(cnt < 0) WRONG
+ GETDATA(trash,cnt);
+ p = MD5Data(trash,cnt);
+ if(md5 && strcmp(md5,p)) {
+ Fatal("Internal MD5 failed.");
+ return 1;
+ default:
+ fprintf(stderr,"List = 0x%x\n",j);
+ Fatal("List had garbage.");
+ return 1;
+
+ }
+
+ }
+ }
+ if(Verbose > 5)
+ putc('\n',stderr);
+ continue;
+ }
+ q = MD5End (&ctx);
+ if(Verbose > 2)
+ printf("Expecting Global MD5 <%s>\n",q);
+ GETFIELD(p,'\n'); /* <MD5> */
+ if(Verbose > 2)
+ printf("Reference Global MD5 <%s>\n",p);
+ if(strcmp(q,p)) {
+ Fatal("MD5 sum doesn't match.");
+ fprintf(stderr,"\tI have:<%s>\n",q);
+ fprintf(stderr,"\tShould have been:<%s>\n",p);
+ return 1;
+ }
+ if (-1 != getc(fd)) {
+ if(!Force) {
+ Fatal("Trailing junk in CTM-file. Can Force with -F.");
+ return 16;
+ }
+ }
+ return 0;
+}
diff --git a/usr.sbin/ctm/ctm/ctm_pass2.c b/usr.sbin/ctm/ctm/ctm_pass2.c
new file mode 100644
index 0000000..bf98e72
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_pass2.c
@@ -0,0 +1,173 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+#define BADREAD 32
+
+/*---------------------------------------------------------------------------*/
+/* Pass2 -- Validate the incomming CTM-file.
+ */
+
+int
+Pass2(FILE *fd)
+{
+ u_char *p,*q,*md5=0;
+ MD5_CTX ctx;
+ int i,j,sep,cnt;
+ u_char *trash=0,*name=0;
+ struct CTM_Syntax *sp;
+ struct stat st;
+ int ret = 0;
+
+ if(Verbose>3)
+ printf("Pass2 -- Checking if CTM-patch will apply\n");
+ MD5Init (&ctx);
+
+ GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
+ GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
+ GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
+ /* XXX Lookup name in /etc/ctm,conf, read stuff */
+ GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
+ /* XXX Verify that this is the next patch to apply */
+ GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
+ GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
+ /* XXX drop or use ? */
+
+ for(;;) {
+ if(trash) {Free(trash), trash = 0;}
+ if(name) {Free(name), name = 0;}
+ if(md5) {Free(md5), md5 = 0;}
+ cnt = -1;
+
+ GETFIELD(p,' ');
+
+ if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
+
+ if(!strcmp(p+3,"_END"))
+ break;
+
+ for(sp=Syntax;sp->Key;sp++)
+ if(!strcmp(p+3,sp->Key))
+ goto found;
+ WRONG
+ found:
+ for(i=0;(j = sp->List[i]);i++) {
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ sep = ' ';
+ else
+ sep = '\n';
+
+ switch (j & CTM_F_MASK) {
+ case CTM_F_Name:
+ GETFIELDCOPY(name,sep);
+ /* XXX Check DR DM rec's for parent-dir */
+ if(j & CTM_Q_Name_New) {
+ /* XXX Check DR FR rec's for item */
+ if(-1 != stat(name,&st)) {
+ fprintf(stderr," %s: %s exists.\n",
+ sp->Key,name);
+ ret |= Exit_Forcible;
+ }
+ break;
+ }
+ if(-1 == stat(name,&st)) {
+ fprintf(stderr," %s: %s doesn't exists.\n",
+ sp->Key,name);
+ ret |= Exit_NotOK;
+ break;
+ }
+ if (j & CTM_Q_Name_Dir) {
+ if((st.st_mode & S_IFMT) != S_IFDIR) {
+ fprintf(stderr,
+ " %s: %s exist, but isn't dir.\n",
+ sp->Key,name);
+ ret |= Exit_NotOK;
+ }
+ break;
+ }
+ if (j & CTM_Q_Name_File) {
+ if((st.st_mode & S_IFMT) != S_IFREG) {
+ fprintf(stderr,
+ " %s: %s exist, but isn't file.\n",
+ sp->Key,name);
+ ret |= Exit_NotOK;
+ }
+ break;
+ }
+ break;
+ case CTM_F_Uid:
+ case CTM_F_Gid:
+ case CTM_F_Mode:
+ GETFIELD(p,sep);
+ break;
+ case CTM_F_MD5:
+ if(!name) WRONG
+ if(j & CTM_Q_MD5_Before) {
+ GETFIELD(p,sep);
+ if((st.st_mode & S_IFMT) == S_IFREG &&
+ strcmp(MD5File(name),p)) {
+ fprintf(stderr," %s: %s md5 mismatch.\n",
+ sp->Key,name);
+ if(j & CTM_Q_MD5_Force) {
+ if(Force)
+ fprintf(stderr," Can and will force.\n");
+ else
+ fprintf(stderr," Could have forced.n");
+ ret |= Exit_Forcible;
+ } else {
+ ret |= Exit_NotOK;
+ }
+ }
+ break;
+ }
+ if(j & CTM_Q_MD5_After) {
+ GETFIELDCOPY(md5,sep);
+ break;
+ }
+ /* Unqualified MD5 */
+ WRONG
+ break;
+ case CTM_F_Count:
+ GETBYTECNT(cnt,sep);
+ break;
+ case CTM_F_Bytes:
+ if(cnt < 0) WRONG
+ GETDATA(trash,cnt);
+ if(!strcmp(sp->Key,"FN")) {
+ p = tempnam(TmpDir,"CTMclient");
+ j = ctm_edit(trash,cnt,name,p);
+ if(j) {
+ fprintf(stderr," %s: %s edit returned %d.\n",
+ sp->Key,name,j);
+ ret |= j;
+ return ret;
+ } else if(strcmp(md5,MD5File(p))) {
+ fprintf(stderr," %s: %s edit fails.\n",
+ sp->Key,name);
+ ret |= Exit_Mess;
+ return ret;
+ }
+ unlink(p);
+ free(p);
+ }
+
+ break;
+ default: WRONG
+ }
+ }
+ }
+ q = MD5End (&ctx);
+ GETFIELD(p,'\n'); /* <MD5> */
+ if(strcmp(q,p)) WRONG
+ if (-1 != getc(fd)) WRONG
+ return ret;
+}
diff --git a/usr.sbin/ctm/ctm/ctm_pass3.c b/usr.sbin/ctm/ctm/ctm_pass3.c
new file mode 100644
index 0000000..d6508be
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_pass3.c
@@ -0,0 +1,174 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+#define BADREAD 32
+
+/*---------------------------------------------------------------------------*/
+/* Pass3 -- Validate the incomming CTM-file.
+ */
+
+int
+Pass3(FILE *fd)
+{
+ u_char *p,*q,buf[BUFSIZ];
+ MD5_CTX ctx;
+ int i,j,sep,cnt;
+ u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
+ struct CTM_Syntax *sp;
+ FILE *ed=0;
+ struct stat st;
+
+ if(Verbose>3)
+ printf("Pass3 -- Applying the CTM-patch\n");
+ MD5Init (&ctx);
+
+ GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
+ GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
+ GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
+ GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
+ GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
+ GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
+
+ for(;;) {
+ if(md5) {Free(md5), md5 = 0;}
+ if(uid) {Free(uid), uid = 0;}
+ if(gid) {Free(gid), gid = 0;}
+ if(mode) {Free(mode), mode = 0;}
+ if(md5before) {Free(md5before), md5before = 0;}
+ if(trash) {Free(trash), trash = 0;}
+ if(name) {Free(name), name = 0;}
+ cnt = -1;
+
+ GETFIELD(p,' ');
+
+ if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
+
+ if(!strcmp(p+3,"_END"))
+ break;
+
+ for(sp=Syntax;sp->Key;sp++)
+ if(!strcmp(p+3,sp->Key))
+ goto found;
+ WRONG
+ found:
+ for(i=0;(j = sp->List[i]);i++) {
+ if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
+ sep = ' ';
+ else
+ sep = '\n';
+
+ switch (j & CTM_F_MASK) {
+ case CTM_F_Name: GETFIELDCOPY(name,sep); break;
+ case CTM_F_Uid: GETFIELDCOPY(uid,sep); break;
+ case CTM_F_Gid: GETFIELDCOPY(gid,sep); break;
+ case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
+ case CTM_F_MD5:
+ if(j & CTM_Q_MD5_Before)
+ GETFIELDCOPY(md5before,sep);
+ else
+ GETFIELDCOPY(md5,sep);
+ break;
+ case CTM_F_Count: GETBYTECNT(cnt,sep); break;
+ case CTM_F_Bytes: GETDATA(trash,cnt); break;
+ default: WRONG
+ }
+ }
+ /* XXX This should go away. Disallow trailing '/' */
+ j = strlen(name)-1;
+ if(name[j] == '/') name[j] = '\0';
+
+ fprintf(stderr,"> %s %s\n",sp->Key,name);
+ if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
+ i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0644);
+ if(i < 0) {
+ perror(name);
+ WRONG
+ }
+ if(cnt != write(i,trash,cnt)) {
+ perror(name);
+ WRONG
+ }
+ close(i);
+ if(strcmp(md5,MD5File(name))) {
+ fprintf(stderr," %s %s MD5 didn't come out right\n",
+ sp->Key,name);
+ WRONG
+ }
+ continue;
+ }
+ if(!strcmp(sp->Key,"FE")) {
+ ed = popen("ed","w");
+ if(!ed) {
+ WRONG
+ }
+ fprintf(ed,"e %s\n",name);
+ if(cnt != fwrite(trash,1,cnt,ed)) {
+ perror(name);
+ pclose(ed);
+ WRONG
+ }
+ fprintf(ed,"w %s\n",name);
+ if(pclose(ed)) {
+ perror("ed");
+ WRONG
+ }
+ if(strcmp(md5,MD5File(name))) {
+ fprintf(stderr," %s %s MD5 didn't come out right\n",
+ sp->Key,name);
+ WRONG
+ }
+ continue;
+ }
+ if(!strcmp(sp->Key,"FN")) {
+ strcpy(buf,name);
+ strcat(buf,".ctm");
+ i = ctm_edit(trash,cnt,name,buf);
+ if(i) {
+ fprintf(stderr," %s %s Edit failed with code %d.\n",
+ sp->Key,name,i);
+ WRONG
+ }
+ rename(buf,name);
+ if(strcmp(md5,MD5File(name))) {
+ fprintf(stderr," %s %s Edit failed MD5 check.\n",
+ sp->Key,name);
+ WRONG
+ }
+ continue;
+ }
+ if(!strcmp(sp->Key,"DM")) {
+ if(0 > mkdir(name,0755)) {
+ sprintf(buf,"mkdir -p %s",name);
+ system(buf);
+ }
+ if(0 > stat(name,&st) || ((st.st_mode & S_IFMT) != S_IFDIR)) {
+ fprintf(stderr,"<%s> mkdir failed\n",name);
+ WRONG
+ }
+ continue;
+ }
+ if(!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR")) {
+ if(0 > unlink(name)) {
+ sprintf(buf,"rm -rf %s",name);
+ system(buf);
+ }
+ continue;
+ }
+ WRONG
+ }
+ q = MD5End (&ctx);
+ GETFIELD(p,'\n');
+ if(strcmp(q,p)) WRONG
+ if (-1 != getc(fd)) WRONG
+ return 0;
+}
diff --git a/usr.sbin/ctm/ctm/ctm_syntax.c b/usr.sbin/ctm/ctm/ctm_syntax.c
new file mode 100644
index 0000000..a2da70a
--- /dev/null
+++ b/usr.sbin/ctm/ctm/ctm_syntax.c
@@ -0,0 +1,66 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include "ctm.h"
+
+/* The fields... */
+#define Name CTM_F_Name
+#define Uid CTM_F_Uid
+#define Gid CTM_F_Gid
+#define Mode CTM_F_Mode
+#define MD5 CTM_F_MD5
+#define Count CTM_F_Count
+#define Bytes CTM_F_Bytes
+
+/* The qualifiers... */
+#define File CTM_Q_Name_File
+#define Dir CTM_Q_Name_Dir
+#define New CTM_Q_Name_New
+#define After CTM_Q_MD5_After
+#define Before CTM_Q_MD5_Before
+#define Chunk CTM_Q_MD5_Chunk
+#define Force CTM_Q_MD5_Force
+
+static int ctmFM[] = /* File Make */
+ { Name|File|New, Uid, Gid, Mode,
+ MD5|After|Chunk, Count, Bytes,0 };
+
+static int ctmFS[] = /* File Substitute */
+ { Name|File, Uid, Gid, Mode,
+ MD5|Before|Force, MD5|After|Chunk, Count, Bytes,0 };
+
+static int ctmFE[] = /* File Edit */
+ { Name|File, Uid, Gid, Mode,
+ MD5|Before, MD5|After, Count, Bytes,0 };
+
+static int ctmFR[] = /* File Remove */
+ { Name|File, MD5|Before, 0 };
+
+static int ctmAS[] = /* Attribute Substitute */
+ { Name, Uid, Gid, Mode, 0 };
+
+static int ctmDM[] = /* Directory Make */
+ { Name|Dir|New , Uid, Gid, Mode, 0 };
+
+static int ctmDR[] = /* Directory Remove */
+ { Name|Dir, 0 };
+
+struct CTM_Syntax Syntax[] = {
+ { "FM", ctmFM },
+ { "FS", ctmFS },
+ { "FE", ctmFE },
+ { "FN", ctmFE },
+ { "FR", ctmFR },
+ { "AS", ctmAS },
+ { "DM", ctmDM },
+ { "DR", ctmDR },
+ { 0, 0} };
diff --git a/usr.sbin/ctm/ctm_scan/Makefile b/usr.sbin/ctm/ctm_scan/Makefile
new file mode 100644
index 0000000..6230e6d
--- /dev/null
+++ b/usr.sbin/ctm/ctm_scan/Makefile
@@ -0,0 +1,15 @@
+#
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+# $Id$
+#
+PROG= ctm_scan
+LDADD+= -lmd
+NOMAN= 1
+CFLAGS+= -Wall
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ctm/ctm_scan/ctm_scan.c b/usr.sbin/ctm/ctm_scan/ctm_scan.c
new file mode 100644
index 0000000..e38a9f0
--- /dev/null
+++ b/usr.sbin/ctm/ctm_scan/ctm_scan.c
@@ -0,0 +1,173 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id: ctm_scan.c,v 1.5 1994/09/25 20:45:55 phk Exp $
+ *
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <dirent.h>
+#include <md5.h>
+
+int barf[256];
+int CheckMode = 0;
+
+int
+pstrcmp(const void *pp, const void *qq)
+{
+ return strcmp(*(char **)pp,*(char **)qq);
+}
+
+int
+Do(char *path)
+{
+ DIR *d;
+ struct dirent *de;
+ struct stat st;
+ int ret=0;
+ u_char buf[BUFSIZ];
+ u_char data[BUFSIZ],*q;
+ int bufp;
+ MD5_CTX ctx;
+ int fd,i,j,k,l,npde,nde=0;
+ char **pde;
+
+ npde = 1;
+ pde = malloc(sizeof *pde * (npde+1));
+ d = opendir(path);
+ if(!d) { perror(path); return 2; }
+ if(!strcmp(path,".")) {
+ *buf = 0;
+ } else {
+ strcpy(buf,path);
+ if(buf[strlen(buf)-1] != '/')
+ strcat(buf,"/");
+ }
+ bufp = strlen(buf);
+ while((de=readdir(d))) {
+ if(!strcmp(de->d_name,".")) continue;
+ if(!strcmp(de->d_name,"..")) continue;
+ if(nde >= npde) {
+ npde *= 2;
+ pde = realloc(pde,sizeof *pde * (npde+1));
+ }
+ strcpy(buf+bufp,de->d_name);
+ if(stat(buf,&st)) {
+ ret |= 1;
+ continue;
+ }
+ pde[nde] = malloc(strlen(buf+bufp)+1);
+ strcpy(pde[nde++],buf+bufp);
+ }
+ closedir(d);
+ if(!nde) return 0;
+ qsort(pde,nde,sizeof *pde, pstrcmp);
+ for(k=0;k<nde;k++) {
+ strcpy(buf+bufp,pde[k]);
+ free(pde[k]);
+ if(stat(buf,&st)) {
+ ret |= 1;
+ continue;
+ }
+ switch(st.st_mode & S_IFMT) {
+ case S_IFDIR:
+ if(!CheckMode) {
+ i = printf("d %s %d %d %d - - -\n",
+ buf,st.st_mode & (~S_IFMT),st.st_uid,st.st_gid);
+ if(!i)
+ exit(-1);
+ }
+ ret |= Do(buf);
+ break;
+ case S_IFREG:
+ fd = open(buf,O_RDONLY);
+ if(fd < 0) {
+ ret |= 1;
+ continue;
+ }
+ MD5Init(&ctx);
+ l = 1;
+ j = 0;
+ while(0 < (i = read(fd,data,sizeof data))) {
+ l = (data[i-1] == '\n');
+ if(!CheckMode)
+ MD5Update(&ctx,data,i);
+ for(q=data;i && !j;i--)
+ if(barf[*q++])
+ j=1;
+ }
+ close(fd);
+ if(CheckMode) {
+ if(j || !l) {
+ i = printf("%s",buf);
+ if(!i) exit(-1);
+ if(j) printf(" Illegal characters.");
+ if(!l) printf(" No final newline.");
+ i = printf(".\n");
+ if(!i) exit(-1);
+ }
+ } else {
+ if(!l)
+ j=2;
+ i = printf("f %s %o %d %d %d %d %s\n",
+ buf,st.st_mode & (~S_IFMT),st.st_uid,st.st_gid,
+ j,st.st_size,MD5End(&ctx));
+ if(!i) exit(-1);
+ }
+ break;
+ default:
+ fprintf(stderr,"%s: type 0%o\n",buf, st.st_mode & S_IFMT);
+ ret |= 4;
+ break;
+ }
+ }
+ free(pde);
+ return ret;
+}
+
+int
+main(int argc, char **argv)
+{
+ /*
+ * Initialize barf[], characters diff/patch will not appreciate.
+ */
+
+ barf[0x00] = 1;
+ barf[0x7f] = 1;
+ barf[0x80] = 1;
+ barf[0xff] = 1;
+
+ /*
+ * -c is CheckMode
+ */
+ if (argc > 1 && !strcmp(argv[1],"-c")) {
+ CheckMode=1;
+ argc--;
+ argv++;
+ }
+
+ /*
+ * First argument, if any, is where to do the work.
+ */
+ if (argc > 1) {
+ if(chdir(argv[1])) {
+ perror(argv[1]);
+ return 2;
+ }
+ }
+
+ /*
+ * Scan the directories recursively.
+ */
+ return Do(".");
+}
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur b/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur
new file mode 100644
index 0000000..bbef14d
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.cvs-cur
@@ -0,0 +1,9 @@
+#!/usr/local/bin/tclsh
+
+set CTMname cvs-cur
+set CTMdest /u4/CTM
+set CTMref /u1/CVS-FreeBSD
+set CTMprefix .
+set CTMcopy $CTMdest/$CTMname
+set CTMtmp $CTMdest/_tmp_$CTMname
+set CTMdate [exec date -u +%Y%m%d%H%M%SZ]
diff --git a/usr.sbin/ctm/mkCTM/ctm_conf.src-cur b/usr.sbin/ctm/mkCTM/ctm_conf.src-cur
new file mode 100644
index 0000000..d81d39f
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/ctm_conf.src-cur
@@ -0,0 +1,9 @@
+#!/usr/local/bin/tclsh
+
+set CTMname src-cur
+set CTMdest /u1/CTM
+set CTMref /u4/ftp/pub/FreeBSD/SRC-current/src
+set CTMprefix .
+set CTMcopy $CTMdest/$CTMname
+set CTMtmp $CTMdest/_tmp_$CTMname
+set CTMdate [exec date -u +%Y%m%d%H%M%SZ]
diff --git a/usr.sbin/ctm/mkCTM/mkCTM b/usr.sbin/ctm/mkCTM/mkCTM
new file mode 100644
index 0000000..35198e9
--- /dev/null
+++ b/usr.sbin/ctm/mkCTM/mkCTM
@@ -0,0 +1,164 @@
+#!/usr/local/bin/tclsh
+
+set CTMignoreCVS 0
+set CTMapply 1
+
+source $argv
+
+set tmp $CTMtmp
+set dd $CTMdest
+set d1 $CTMcopy
+set d2 $CTMref
+set foo $CTMdate
+set foo $CTMprefix
+set foo $CTMname
+
+exec sh -x -c "rm -f ${tmp}.*" >&@ stdout
+
+set f1 [open "| ./ctm_scan $d1"]
+set f2 [open "| ./ctm_scan $d2"]
+
+set fo_del [open $tmp.del w]
+set fo_rmdir [open $tmp.rmdir w]
+set fo_mkdir [open $tmp.mkdir w]
+set fo_files [open $tmp.files w]
+set changes 0
+
+####
+# Find CTM#
+for {set i 0} {1} {incr i} {
+ if {[file exists [format "%s/$CTMname.%04d" $dd $i]]} continue
+ if {[file exists [format "%s/$CTMname.%04d.gz" $dd $i]]} continue
+ break
+}
+set CTMnbr $i
+
+puts "Doing CTMname $CTMname CTMnbr $CTMnbr CTMdate $CTMdate"
+
+#####
+# Type Name Mode User Group Barf Size Hash
+
+proc CTMadd {t n m u g b s h} {
+ global fo_files fo_mkdir changes d2
+ puts stderr "A $b $t $n"
+ if {$t == "d"} {
+ puts $fo_mkdir "CTMDM $n $u $g $m"
+ incr changes
+ return
+ }
+ puts $fo_files "CTMFM $n $u $g $m $h $s"
+ flush $fo_files
+ exec cat $d2/$n >@ $fo_files
+ puts $fo_files ""
+ incr changes
+ return
+}
+proc CTMdel {t n m u g b s h} {
+ global fo_del fo_rmdir changes
+ puts stderr "D $b $t $n"
+ if {$t == "d"} {
+ puts $fo_rmdir "CTMDR $n"
+ incr changes
+ return
+ }
+ puts $fo_del "CTMFR $n $h"
+ incr changes
+ return
+}
+proc CTMchg {t1 n1 m1 u1 g1 b1 s1 h1 t2 n2 m2 u2 g2 b2 s2 h2} {
+ global fo_files d2 d1 changes
+ if {$t1 == "d" && $t2 == "d"} {
+ return
+ }
+ if {$t1 == "d" || $t2 == "d"} {
+ CTMdel $t1 $n1 $m1 $u1 $g1 $b1 $s1 $h1
+ CTMadd $t2 $n2 $m2 $u2 $g2 $b2 $s2 $h2
+ return
+ }
+ if {"x$h1" == "x$h2" && $s1 == $s2} {
+ return
+ puts stderr "M $b1$b2 $t1$t2 $n1"
+ puts $fo_files "CTMFA $n2 $u2 $g2 $m2 $h2"
+ incr changes
+ return
+ }
+ if {$b1 == "0" && $b2 == "0"} {
+ set i [catch "exec diff -n $d1/$n1 $d2/$n2 > tmp" j]
+ set s [file size tmp]
+ if {$s < $s2} {
+ puts stderr "E $b1$b2 $t1$t2 $n1"
+ puts $fo_files "CTMFN $n1 $u2 $g2 $m2 $h1 $h2 $s"
+ flush $fo_files
+ exec cat tmp >@ $fo_files
+ puts $fo_files ""
+ incr changes
+ return
+ }
+ }
+ puts stderr "R $b1$b2 $t1$t2 $n1"
+ puts $fo_files "CTMFS $n2 $u2 $g2 $m2 $h1 $h2 $s2"
+ flush $fo_files
+ exec cat $d2/$n2 >@ $fo_files
+ puts $fo_files ""
+ incr changes
+ return
+}
+#####
+set l1 ""
+set l2 ""
+
+while 1 {
+
+ if {$l1 == ""} {gets $f1 l1}
+
+ if {$l2 == ""} {gets $f2 l2}
+
+ if {$l1 == "" && $l2 == ""} break
+
+ set n1 [lindex $l1 1]
+ set n2 [lindex $l2 1]
+
+ if {$l1 == $l2} { set l1 "" ; set l2 "" ; continue }
+
+ if {$CTMignoreCVS } {
+ if {[regexp {/CVS/} $l1]} {set l1 ""; continue }
+ if {[regexp {/CVS/} $l2]} {set l2 ""; continue }
+ }
+
+ if {$l1 == "" } { eval CTMadd $l2 ; set l2 "" ; continue }
+
+ if {$l2 == "" } { eval CTMdel $l1 ; set l1 "" ; continue }
+
+ if {$n1 < $n2 } { eval CTMdel $l1 ; set l1 "" ; continue }
+
+ if {$n1 > $n2 } { eval CTMadd $l2 ; set l2 "" ; continue }
+
+ if {$n1 == $n2} { eval CTMchg $l1 $l2 ; set l1 "" ; set l2 "" ; continue }
+}
+
+close $fo_del
+close $fo_rmdir
+close $fo_mkdir
+close $fo_files
+
+exec echo CTM_BEGIN 2.0 $CTMname $CTMnbr $CTMdate $CTMprefix > $tmp.begin
+exec echo -n "CTM_END " >> $tmp.end
+set m [exec cat $tmp.begin $tmp.del $tmp.rmdir $tmp.mkdir $tmp.files $tmp.end | /sbin/md5]
+exec echo "$m" >> $tmp.end
+
+if {!$changes} {
+ puts "no changes"
+ exec sh -c "rm -f ${tmp}.*"
+ exit 0
+}
+flush stdout
+set nm [format "%s/%s.%04d" $dd $CTMname $CTMnbr]
+
+exec cat $tmp.begin $tmp.del $tmp.rmdir $tmp.mkdir $tmp.files $tmp.end \
+ | gzip -9 > ${nm}.gz
+
+exec sh -x -c "rm -f ${tmp}.*" >&@ stdout
+
+if {$CTMapply} {
+ exec sh -e -x -c "cd $CTMcopy ; /root/CTM/ctm -v -v -v ${nm}.gz" >&@ stdout
+}
diff --git a/usr.sbin/dbsym/Makefile b/usr.sbin/dbsym/Makefile
new file mode 100644
index 0000000..e1fbf2c
--- /dev/null
+++ b/usr.sbin/dbsym/Makefile
@@ -0,0 +1,6 @@
+# $Id$
+
+PROG= dbsym
+NOMAN= noman
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/dbsym/dbsym.c b/usr.sbin/dbsym/dbsym.c
new file mode 100644
index 0000000..833627c
--- /dev/null
+++ b/usr.sbin/dbsym/dbsym.c
@@ -0,0 +1,255 @@
+/* Written by Pace Willisson (pace@blitz.com)
+ * and placed in the public domain.
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: dbsym.c,v 1.3 1994/01/19 03:52:25 nate Exp $";
+#endif /* not lint */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <machine/param.h>
+#include <vm/vm_param.h>
+#include <vm/lock.h>
+#include <vm/pmap.h>
+#include <machine/pmap.h>
+#include <machine/vmparam.h>
+
+#define FILE_OFFSET(vadr) (((vadr) - text_adr) - N_DATADDR(hdr) + \
+ N_DATOFF(hdr) + N_TXTADDR(hdr))
+
+u_int text_adr = KERNBASE;
+
+struct nlist *old_syms;
+int num_old_syms;
+char *old_strtab;
+int old_strtab_size;
+
+struct nlist *new_syms;
+int num_new_syms;
+int new_syms_bytes;
+char *new_strtab;
+int new_strtab_size;
+
+int db_symtabsize_adr;
+int db_symtab_adr;
+
+int avail;
+
+int force = 0;
+int zap_locals = 0;
+int debugging = 0;
+
+usage ()
+{
+ fprintf (stderr, "usage: dbsym [-fgx] [-T addr] file\n");
+ exit (1);
+}
+
+struct exec hdr;
+
+main (argc, argv)
+char **argv;
+{
+ FILE *f;
+ char *name;
+ extern int optind;
+ int c, i;
+ int need;
+ char *buf, *p;
+ struct nlist *nsp, *sp;
+ int len;
+
+
+ while ((c = getopt (argc, argv, "fgxT:")) != EOF) {
+ switch (c) {
+ case 'f':
+ force = 1;
+ break;
+ case 'g':
+ debugging = 1;
+ break;
+ case 'x':
+ zap_locals = 1;
+ break;
+ case 'T':
+ text_adr = strtoul(optarg, &p, 16);
+ if (*p)
+ err("illegal text address: %s", optarg);
+ break;
+ default:
+ usage ();
+ }
+ }
+
+ if (optind >= argc)
+ usage ();
+
+ name = argv[optind++];
+
+ if (optind != argc)
+ usage ();
+
+ if ((f = fopen (name, "r+")) == NULL) {
+ fprintf (stderr, "can't open %s\n", name);
+ exit (1);
+ }
+
+ if (fread ((char *)&hdr, sizeof hdr, 1, f) != 1) {
+ fprintf (stderr, "can't read header\n");
+ exit (1);
+ }
+
+ if (N_BADMAG (hdr)) {
+ fprintf (stderr, "bad magic number\n");
+ exit (1);
+ }
+
+ if (hdr.a_syms == 0) {
+ fprintf (stderr, "no symbols\n");
+ exit (1);
+ }
+
+ fseek (f, N_STROFF (hdr), 0);
+ if (fread ((char *)&old_strtab_size, sizeof (int), 1, f) != 1) {
+ fprintf (stderr, "can't read old strtab size\n");
+ exit (1);
+ }
+
+ if ((old_syms = (struct nlist *)malloc (hdr.a_syms)) == NULL
+ || ((old_strtab = malloc (old_strtab_size)) == NULL)
+ || ((new_syms = (struct nlist *)malloc (hdr.a_syms)) == NULL)
+ || ((new_strtab = malloc (old_strtab_size)) == NULL)) {
+ fprintf (stderr, "out of memory\n");
+ exit (1);
+ }
+
+ fseek (f, N_SYMOFF (hdr), 0);
+ if (fread ((char *)old_syms, hdr.a_syms, 1, f) != 1) {
+ fprintf (stderr, "can't read symbols\n");
+ exit (1);
+ }
+
+ fseek (f, N_STROFF (hdr), 0);
+ if (fread ((char *)old_strtab, old_strtab_size, 1, f) != 1) {
+ fprintf (stderr, "can't read string table\n");
+ exit (1);
+ }
+
+ num_old_syms = hdr.a_syms / sizeof (struct nlist);
+
+ new_strtab_size = 4;
+
+ nsp = new_syms;
+ for (i = 0, sp = old_syms; i < num_old_syms; i++, sp++) {
+ if (zap_locals && !(sp->n_type & N_EXT))
+ continue;
+
+ if (sp->n_type & N_STAB)
+ switch (sp->n_type & ~N_EXT) {
+ case N_SLINE:
+ if (debugging)
+ *nsp++ = *sp;
+ continue;
+ case N_FUN:
+ case N_PSYM:
+ case N_SO:
+ if (!debugging)
+ continue;
+ goto skip_tests;
+ break;
+ default:
+ continue;
+ }
+
+ if ((sp->n_type & ~N_EXT) == N_UNDF)
+ continue;
+
+ if (!debugging && (sp->n_type & ~N_EXT) == N_FN)
+ continue;
+
+ if (sp->n_un.n_strx == 0)
+ continue;
+
+ if (sp->n_value < text_adr)
+ continue;
+
+ if (sp->n_value > (text_adr + hdr.a_text + hdr.a_data +
+ hdr.a_bss))
+ continue;
+
+ skip_tests:
+
+ name = old_strtab + sp->n_un.n_strx;
+
+ len = strlen (name);
+
+ if (len == 0)
+ continue;
+
+ if (strcmp (name, "gcc_compiled.") == 0)
+ continue;
+
+ if (strcmp (name, "gcc2_compiled.") == 0)
+ continue;
+
+ if (strcmp (name, "___gnu_compiled_c") == 0)
+ continue;
+
+ *nsp = *sp;
+
+ nsp->n_un.n_strx = new_strtab_size;
+ strcpy (new_strtab + new_strtab_size, name);
+ new_strtab_size += len + 1;
+ nsp++;
+
+ if (strcmp (name, "_db_symtab") == 0)
+ db_symtab_adr = sp->n_value;
+ if (strcmp (name, "_db_symtabsize") == 0)
+ db_symtabsize_adr = sp->n_value;
+ }
+
+ if (db_symtab_adr == 0 || db_symtabsize_adr == 0)
+ if (!force) {
+ fprintf (stderr, "couldn't find db_symtab symbols\n");
+ exit (1);
+ } else
+ exit (0);
+
+ *(int *)new_strtab = new_strtab_size;
+ num_new_syms = nsp - new_syms;
+ new_syms_bytes = num_new_syms * sizeof (struct nlist);
+
+ need = sizeof (int)
+ + num_new_syms * sizeof (struct nlist)
+ + new_strtab_size;
+
+ fseek (f, FILE_OFFSET (db_symtabsize_adr), 0);
+
+ if (fread ((char *)&avail, sizeof (int), 1, f) != 1) {
+ fprintf (stderr, "can't read symtabsize\n");
+ exit (1);
+ }
+
+ printf ("dbsym: need %d; avail %d\n", need, avail);
+
+ if (need > avail) {
+ fprintf (stderr, "not enough room in db_symtab array\n");
+ exit (1);
+ }
+
+ fseek (f, FILE_OFFSET (db_symtab_adr), 0);
+ fwrite ((char *)&new_syms_bytes, sizeof (int), 1, f);
+ fwrite ((char *)new_syms, new_syms_bytes, 1, f);
+ fwrite (new_strtab, new_strtab_size, 1, f);
+ fflush (f);
+
+ if (feof (f) || ferror (f)) {
+ fprintf (stderr, "write error\n");
+ exit (1);
+ }
+ exit (0);
+}
+
diff --git a/usr.sbin/dev_mkdb/Makefile b/usr.sbin/dev_mkdb/Makefile
new file mode 100644
index 0000000..8737b50
--- /dev/null
+++ b/usr.sbin/dev_mkdb/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= dev_mkdb
+MAN8= 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 0000000..9369b2b
--- /dev/null
+++ b/usr.sbin/dev_mkdb/dev_mkdb.8
@@ -0,0 +1,81 @@
+.\" 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.
+.\"
+.\" @(#)dev_mkdb.8 8.1 (Berkeley) 6/6/93
+.\"
+.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 0000000..682c041
--- /dev/null
+++ b/usr.sbin/dev_mkdb/dev_mkdb.c
@@ -0,0 +1,181 @@
+/*-
+ * 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[] = "@(#)dev_mkdb.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#undef DIRBLKSIZ
+#include <dirent.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <db.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+
+void err __P((const char *, ...));
+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("%s: %s", _PATH_DEV, strerror(errno));
+
+ 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("%s: %s", dbtmp, strerror(errno));
+
+ /*
+ * 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)) {
+ (void)fprintf(stderr,
+ "dev_mkdb: %s: %s\n", dp->d_name, strerror(errno));
+ 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("dbput %s: %s\n", dbtmp, strerror(errno));
+ }
+ (void)(db->close)(db);
+ if (rename(dbtmp, dbname))
+ err("rename %s to %s: %s", dbtmp, dbname, strerror(errno));
+ exit(0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: dev_mkdb\n");
+ exit(1);
+}
+
+#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, "dev_mkdb: ");
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void)fprintf(stderr, "\n");
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/diskpart/Makefile b/usr.sbin/diskpart/Makefile
new file mode 100644
index 0000000..bf623cb
--- /dev/null
+++ b/usr.sbin/diskpart/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= diskpart
+MAN8= 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 0000000..0b02de2
--- /dev/null
+++ b/usr.sbin/diskpart/diskpart.8
@@ -0,0 +1,143 @@
+.\" 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.
+.\"
+.\" @(#)diskpart.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.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 0000000..c89d0f1
--- /dev/null
+++ b/usr.sbin/diskpart/diskpart.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)diskpart.c 8.1 (Berkeley) 6/6/93";
+#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: disktab [ -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_long *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 (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 0000000..1eb5de9
--- /dev/null
+++ b/usr.sbin/edquota/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= edquota
+MAN8= 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 0000000..f5bf705
--- /dev/null
+++ b/usr.sbin/edquota/edquota.8
@@ -0,0 +1,150 @@
+.\" 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.
+.\"
+.\" @(#)edquota.8 8.1 (Berkeley) 6/6/93
+.\"
+.TH EDQUOTA 8 "June 6, 1993"
+.UC 5
+.SH NAME
+edquota \- edit user quotas
+.SH SYNOPSIS
+.B edquota
+[
+.I \-u
+] [
+.I \-p
+proto-username
+]
+username ...
+.br
+.B edquota
+.I \-g
+[
+.I \-p
+proto-groupname
+]
+groupname ...
+.br
+.B edquota
+.I -t
+[
+.I -u
+]
+.br
+.B edquota
+.I -t
+.I -g
+.br
+.SH DESCRIPTION
+.I Edquota
+is a quota editor.
+By default, or if the \fI-u\fP 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
+.IR /etc/fstab .
+An editor is invoked on the ASCII file.
+The editor invoked is
+.IR vi (1)
+unless the environment variable 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 \fI-t\fP 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,
+.I edquota
+reads the temporary file and modifies the binary
+quota files to reflect the changes made.
+.PP
+If the
+.B \-p
+option is specified,
+.I 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 \fI-g\fP flag is specified,
+.I edquota
+is invoked to edit the quotas of
+one or more groups specified on the command line.
+The \fI-p\fP flag can be specified in conjunction with
+the \fI-g\fP 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
+.IR /usr/include/ufs/quota.h .
+The \fI-t\fP flag can be used to change the grace period.
+By default, or when invoked with the \fI-u\fP flag,
+the grace period is set for all the filesystems with user
+quotas specified in
+.IR /etc/fstab .
+When invoked with the \fI-g\fP flag the grace period is
+set for all the filesystems with group quotas specified in
+.IR /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
+.DT
+\fIquota.user\fP at the filesystem root with user quotas
+.br
+\fIquota.group\fP at the filesystem root with group quotas
+.br
+/etc/fstab to find filesystem names and locations
+.SH SEE ALSO
+quota(1),
+quotactl(2),
+fstab(5),
+quotacheck(8), quotaon(8), 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 0000000..3646720
--- /dev/null
+++ b/usr.sbin/edquota/edquota.c
@@ -0,0 +1,722 @@
+/*
+ * 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[] = "@(#)edquota.c 8.1 (Berkeley) 6/6/93";
+#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 <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, (long)(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, (long)id * (long)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 0000000..92546f7
--- /dev/null
+++ b/usr.sbin/edquota/pathnames.h
@@ -0,0 +1,39 @@
+/*
+ * 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>
+
+#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 0000000..389a137
--- /dev/null
+++ b/usr.sbin/eeprom/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= eeprom
+MAN8= eeprom.0
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/eeprom/eeprom.8 b/usr.sbin/eeprom/eeprom.8
new file mode 100644
index 0000000..07c3969
--- /dev/null
+++ b/usr.sbin/eeprom/eeprom.8
@@ -0,0 +1,69 @@
+.\" 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.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)eeprom.8 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.Dt EEPROM 8
+.Os BSD 4.4
+.Sh NAME
+.Nm eeprom
+.Nd openprom control utility
+.Sh SYNOPSIS
+.Nm eeprom
+.Op Ar name Ar ...
+.Op Ar name=value Ar ...
+.Sh DESCRIPTION
+The
+.Nm
+utility
+is used to display
+and modify options fields in the SPARCstation openprom.
+.Pp
+When invoked with no arguments,
+.Nm
+display the values of all options. Otherwise, fields are displayed or
+set (in the order specified on the command line).
+.Sh FILES
+.Bl -tag -width /dev/openprom -compact
+.It Pa /dev/openprom
+the openprom device
+.El
+.Sh SEE ALSO
+.Xr openprom 4
+.Sh HISTORY
+The
+.Nm eeprom
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/eeprom/eeprom.c b/usr.sbin/eeprom/eeprom.c
new file mode 100644
index 0000000..2015fed
--- /dev/null
+++ b/usr.sbin/eeprom/eeprom.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 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 Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)eeprom.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * eeprom - openprom control utility
+ *
+ * usage:
+ *
+ * eeprom [field] [field=value]
+ */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <machine/openpromio.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "pathnames.h"
+
+static char openprom[] = _PATH_OPENPROM;
+static char usage[] = "usage: %s [field] [field=value]\n";
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register char *cp;
+ register int i, op, fd, flags, status;
+ register struct opiocdesc *dp;
+ struct opiocdesc desc;
+ char buf[1024], buf2[sizeof(buf)];
+ char *prog, *name;
+
+ /* Determine simple program name for error messages */
+ if (cp = rindex(argv[0], '/'))
+ prog = cp + 1;
+ else
+ prog = argv[0];
+
+ /* Parse flags */
+ opterr = 0;
+ while ((op = getopt(argc, argv, "")) != EOF)
+ switch (op) {
+
+ default:
+ (void) fprintf(stderr, usage, prog);
+ exit(1);
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* Determine flags and open device */
+ flags = O_RDONLY;
+ for (i = 0; i < argc; ++i)
+ if (index(argv[i], '=') != NULL) {
+ flags = O_RDWR;
+ break;
+ }
+ if ((fd = open(openprom, flags, 0)) < 0) {
+ fprintf(stderr, "%s: open %s: %s\n",
+ prog, openprom, strerror(errno));
+ exit(1);
+ }
+
+ dp = &desc;
+ bzero(dp, sizeof(*dp));
+ if (ioctl(fd, OPIOCGETOPTNODE, &dp->op_nodeid) < 0) {
+ fprintf(stderr, "%s: get optionsnode: %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+
+ if (argc <= 0) {
+ /* Prime the pump with a zero length name */
+ dp->op_name = buf;
+ dp->op_name[0] = '\0';
+ dp->op_namelen = 0;
+ dp->op_buf = buf2;
+ for (;;) {
+ /* Get the next property name */
+ dp->op_buflen = sizeof(buf);
+ if (ioctl(fd, OPIOCNEXTPROP, dp) < 0) {
+ fprintf(stderr, "%s: get next: %s\n",
+ prog, strerror(errno));
+ exit(1);
+ }
+
+ /* Zero length name means we're done */
+ if (dp->op_buflen <= 0)
+ break;
+
+ /* Clever hack, swap buffers */
+ cp = dp->op_buf;
+ dp->op_buf = dp->op_name;
+ dp->op_name = cp;
+ dp->op_namelen = dp->op_buflen;
+
+ /* Get the value */
+ dp->op_buflen = sizeof(buf);
+ if (ioctl(fd, OPIOCGET, dp) < 0) {
+ fprintf(stderr, "%s: get \"%s\": %s\n",
+ prog, cp, strerror(errno));
+ exit(1);
+ }
+ printf("%.*s=%.*s\n", dp->op_namelen, dp->op_name,
+ dp->op_buflen, dp->op_buf);
+ }
+ exit(0);
+ }
+
+ status = 0;
+ for (i = 0; i < argc; ++i) {
+ dp->op_name = name = argv[i];
+ cp = index(name, '=');
+ if (cp) {
+ *cp++ = '\0';
+ dp->op_buf = cp;
+ dp->op_buflen = strlen(dp->op_buf);
+ } else {
+ dp->op_buf = buf;
+ dp->op_buflen = sizeof(buf);
+ }
+ dp->op_namelen = strlen(name);
+ if (ioctl(fd, cp ? OPIOCSET : OPIOCGET, dp) < 0) {
+ fprintf(stderr, "%s: %s \"%s\": %s\n",
+ prog, cp ? "set" : "get", name, strerror(errno));
+ status |= 1;
+ continue;
+ }
+
+ /* If setting an entry, we're done */
+ if (cp)
+ continue;
+ if (dp->op_buflen < 0) {
+ fprintf(stderr, "%s: \"%s\" not found\n", prog, name);
+ status |= 1;
+ continue;
+ }
+ if (dp->op_buflen >= sizeof(buf)) {
+ fprintf(stderr, "%s: \"%s\" truncated\n", prog, name);
+ status |= 1;
+ /* fall thorugh and print truncated value */
+ }
+ printf("%s=%.*s\n", name, dp->op_buflen, buf);
+ }
+
+ exit(status);
+}
diff --git a/usr.sbin/eeprom/pathnames.h b/usr.sbin/eeprom/pathnames.h
new file mode 100644
index 0000000..8df60ce
--- /dev/null
+++ b/usr.sbin/eeprom/pathnames.h
@@ -0,0 +1,45 @@
+/*-
+ * 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 Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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
+ */
+
+#define _PATH_OPENPROM "/dev/openprom"
diff --git a/usr.sbin/fdformat/Makefile b/usr.sbin/fdformat/Makefile
new file mode 100644
index 0000000..e489ebc
--- /dev/null
+++ b/usr.sbin/fdformat/Makefile
@@ -0,0 +1,9 @@
+#
+PROG = fdformat
+
+# the -I's seem to be confusing, but necessery this way
+# (so the right <unistd.h> will be found in /usr/include, and the
+# "../i386/isa/ic/nec765.h" included from fdreg.h is accessible, too)
+CFLAGS+= -Wall
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fdformat/fdformat.1 b/usr.sbin/fdformat/fdformat.1
new file mode 100644
index 0000000..2b27f7f
--- /dev/null
+++ b/usr.sbin/fdformat/fdformat.1
@@ -0,0 +1,133 @@
+.\" Copyright (C) 1993 by Joerg Wunsch, Dresden
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED 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(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (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 September 16, 1993
+.Os
+.Dt FDFORMAT 1
+.Sh NAME
+.Nm fdformat
+.Nd format floppy disks
+.Sh SYNOPSIS
+.Nm fdformat
+.Bq Fl q
+.Bq Fl v
+.Bq Fl n
+.Bq Fl f Ar capacity
+.Bq Fl c Ar cyls
+.Bq Fl s Ar secs
+.Bq Fl h Ar heads
+.br
+.Bq Fl r Ar rate
+.Bq Fl g Ar gap3len
+.Bq Fl i Ar intleave
+.Bq Fl S Ar secshft
+.Bq Fl F Ar fillbyte
+.Bq Fl t Ar steps_per_track
+.Ar device_name
+.Sh DESCRIPTION
+.Nm Fdformat
+formats a floppy disk at device
+.Ar device_name .
+.Ar Device_name
+should be a character device; it may be given either with a full path
+name of a raw device node for a floppy disk drive
+.Pq e.\ g. Pa /dev/rfd0 ,
+or default name in an abbreviated form
+.Pq e.\ g. Em fd0 .
+In the latter case, the name is constructed by prepending
+.Pa /dev/r
+and appending a
+.Em .capacity
+to the
+.Ar device_name .
+Note that any geometry constraints of the device node
+.Pq minor device number
+are meaningless, since they're overridden by
+.Nm fdformat .
+.Pp
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl q
+supress any normal output from the command, and don't ask the
+user for a confirmation whether to format the floppy disk at
+.Ar device_name .
+.It Fl f Ar capacity
+The normal way to specify the desired formatting parameters.
+.Ar Capacity
+is the number of kilobytes to format.
+.It Fl n
+Don't verify floppy after formatting.
+.It Fl v
+Don't format, verify only.
+.It Fl c Ar cyls
+.It Fl s Ar secs
+.It Fl h Ar heads
+.It Fl r Ar rate
+.It Fl g Ar gap3len
+.It Fl i Ar intleave
+.It Fl S Ar secshft
+.It Fl F Ar fillbyte
+.It Fl t Ar steps_per_track
+An alternate method to specify the geometry data to write to the floppy disk.
+.El
+
+If the
+.Fl q
+flag has not been specified, the user is asked for a confirmation
+of the intended formatting process. In order to continue, an answer
+of
+.Dq y
+must be given.
+.Sh DIAGNOSTICS
+Unless
+.Fl q
+has been specified, a single letter is printed to standard output
+to inform the user about the progress of work.
+First, an
+.Sq Em F
+is printed when the track(s) is being formatted, then a
+.Sq Em V
+while it's being verified, and if an error has been detected, it
+will finally change to
+.Sq Em E .
+.Pp
+An exit status of 0 is returned upon successful operation. Exit status
+1 is returned on any errors during floppy formatting, and an exit status
+of 2 reflects invalid arguments given to the program (along with an
+appropriate information written to diagnostic output).
+.Sh SEE ALSO
+.Xr fd 4 .
+.Sh HISTORY
+.Nm Fdformat
+has been developed for 386BSD 0.1
+and upgraded to the new
+.Xr fd 4
+floppy disk driver. It later became part of the
+.Em FreeBSD
+system, release 1.1.
+.Sh AUTHOR
+The program has been contributed by
+.if n Joerg Wunsch,
+.if t J\(:org Wunsch,
+Dresden, with changes by Serge Vakulenko and Andrew A. Chernov, Moscow.
diff --git a/usr.sbin/fdformat/fdformat.c b/usr.sbin/fdformat/fdformat.c
new file mode 100644
index 0000000..b43af82
--- /dev/null
+++ b/usr.sbin/fdformat/fdformat.c
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 1992-1994 by Joerg Wunsch, Dresden
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED 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(S) BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * FreeBSD:
+ * format a floppy disk
+ *
+ * Added FD_GTYPE ioctl, verifying, proportional indicators.
+ * Serge Vakulenko, vak@zebub.msk.su
+ * Sat Dec 18 17:45:47 MSK 1993
+ *
+ * Final adaptation, change format/verify logic, add separate
+ * format gap/interleave values
+ * Andrew A. Chernov, ache@astral.msk.su
+ * Thu Jan 27 00:47:24 MSK 1994
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include <errno.h>
+#include <machine/ioctl_fd.h>
+
+static void
+format_track(int fd, int cyl, int secs, int head, int rate,
+ int gaplen, int secsize, int fill,int interleave)
+{
+ struct fd_formb f;
+ register int i,j;
+ int il[FD_MAX_NSEC + 1];
+
+ memset(il,0,sizeof il);
+ for(j = 0, i = 1; i <= secs; i++) {
+ while(il[(j%secs)+1]) j++;
+ il[(j%secs)+1] = i;
+ j += interleave;
+ }
+
+ f.format_version = FD_FORMAT_VERSION;
+ f.head = head;
+ f.cyl = cyl;
+ f.transfer_rate = rate;
+
+ f.fd_formb_secshift = secsize;
+ f.fd_formb_nsecs = secs;
+ f.fd_formb_gaplen = gaplen;
+ f.fd_formb_fillbyte = fill;
+ for(i = 0; i < secs; i++) {
+ f.fd_formb_cylno(i) = cyl;
+ f.fd_formb_headno(i) = head;
+ f.fd_formb_secno(i) = il[i+1];
+ f.fd_formb_secsize(i) = secsize;
+ }
+ if(ioctl(fd, FD_FORM, (caddr_t)&f) < 0) {
+ perror("\nfdformat: ioctl(FD_FORM)");
+ exit(1);
+ }
+}
+
+static int
+verify_track(int fd, int track, int tracksize)
+{
+ static char *buf = 0;
+ static int bufsz = 0;
+ int fdopts = -1, ofdopts, rv = 0;
+
+ if (ioctl(fd, FD_GOPTS, &fdopts) < 0)
+ perror("warning: ioctl(FD_GOPTS)");
+ else {
+ ofdopts = fdopts;
+ fdopts |= FDOPT_NORETRY;
+ (void)ioctl(fd, FD_SOPTS, &fdopts);
+ }
+
+ if (bufsz < tracksize) {
+ if (buf)
+ free (buf);
+ bufsz = tracksize;
+ buf = 0;
+ }
+ if (! buf)
+ buf = malloc (bufsz);
+ if (! buf) {
+ fprintf (stderr, "\nfdformat: out of memory\n");
+ exit (2);
+ }
+ if (lseek (fd, (long) track*tracksize, 0) < 0)
+ rv = -1;
+ /* try twice reading it, without using the normal retrier */
+ else if (read (fd, buf, tracksize) != tracksize
+ && read (fd, buf, tracksize) != tracksize)
+ rv = -1;
+ if(fdopts != -1)
+ (void)ioctl(fd, FD_SOPTS, &ofdopts);
+ return (rv);
+}
+
+static const char *
+makename(const char *arg, const char *suffix)
+{
+ static char namebuff[20]; /* big enough for "/dev/rfd0a"... */
+
+ memset(namebuff, 0, 20);
+ if(*arg == '\0') /* ??? */
+ return arg;
+ if(*arg == '/') /* do not convert absolute pathnames */
+ return arg;
+ strcpy(namebuff, "/dev/r");
+ strncat(namebuff, arg, 3);
+ strcat(namebuff, suffix);
+ return namebuff;
+}
+
+static void
+usage (void)
+{
+ printf("Usage:\n\tfdformat [-q] [-n | -v] [-f #] [-c #] [-s #] [-h #]\n");
+ printf("\t\t [-r #] [-g #] [-i #] [-S #] [-F #] [-t #] devname\n");
+ printf("Options:\n");
+ printf("\t-q\tsupress any normal output, don't ask for confirmation\n");
+ printf("\t-n\tdon't verify floppy after formatting\n");
+ printf("\t-v\tdon't format, verify only\n");
+ printf("\t-f #\tspecify desired floppy capacity, in kilobytes;\n");
+ printf("\t\tvalid choices are 360, 720, 800, 820, 1200, 1440, 1480, 1720\n");
+ printf("\tdevname\tthe full name of floppy device or in short form fd0, fd1\n");
+ printf("Obscure options:\n");
+ printf("\t-c #\tspecify number of cylinders, 40 or 80\n");
+ printf("\t-s #\tspecify number of sectors per track, 9, 10, 15 or 18\n");
+ printf("\t-h #\tspecify number of floppy heads, 1 or 2\n");
+ printf("\t-r #\tspecify data rate, 250, 300 or 500 kbps\n");
+ printf("\t-g #\tspecify gap length\n");
+ printf("\t-i #\tspecify interleave factor\n");
+ printf("\t-S #\tspecify sector size, 0=128, 1=256, 2=512 bytes\n");
+ printf("\t-F #\tspecify fill byte\n");
+ printf("\t-t #\tnumber of steps per track\n");
+ exit(2);
+}
+
+static int
+yes (void)
+{
+ char reply [256], *p;
+
+ reply[sizeof(reply)-1] = 0;
+ for (;;) {
+ fflush(stdout);
+ if (! fgets (reply, sizeof(reply)-1, stdin))
+ return (0);
+ for (p=reply; *p==' ' || *p=='\t'; ++p)
+ continue;
+ if (*p=='y' || *p=='Y')
+ return (1);
+ if (*p=='n' || *p=='N' || *p=='\n' || *p=='\r')
+ return (0);
+ printf("Answer `yes' or `no': ");
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int format = -1, cyls = -1, secs = -1, heads = -1, intleave = -1;
+ int rate = -1, gaplen = -1, secsize = -1, steps = -1;
+ int fill = 0xf6, quiet = 0, verify = 1, verify_only = 0;
+ int fd, c, track, error, tracks_per_dot, bytes_per_track, errs;
+ const char *devname, *suffix;
+ struct fd_type fdt;
+
+ while((c = getopt(argc, argv, "f:c:s:h:r:g:S:F:t:i:qvn")) != -1)
+ switch(c) {
+ case 'f': /* format in kilobytes */
+ format = atoi(optarg);
+ break;
+
+ case 'c': /* # of cyls */
+ cyls = atoi(optarg);
+ break;
+
+ case 's': /* # of secs per track */
+ secs = atoi(optarg);
+ break;
+
+ case 'h': /* # of heads */
+ heads = atoi(optarg);
+ break;
+
+ case 'r': /* transfer rate, kilobyte/sec */
+ rate = atoi(optarg);
+ break;
+
+ case 'g': /* length of GAP3 to format with */
+ gaplen = atoi(optarg);
+ break;
+
+ case 'S': /* sector size shift factor (1 << S)*128 */
+ secsize = atoi(optarg);
+ break;
+
+ case 'F': /* fill byte, C-like notation allowed */
+ fill = (int)strtol(optarg, (char **)0, 0);
+ break;
+
+ case 't': /* steps per track */
+ steps = atoi(optarg);
+ break;
+
+ case 'i': /* interleave factor */
+ intleave = atoi(optarg);
+ break;
+
+ case 'q':
+ quiet = 1;
+ break;
+
+ case 'n':
+ verify = 0;
+ break;
+
+ case 'v':
+ verify = 1;
+ verify_only = 1;
+ break;
+
+ case '?': default:
+ usage();
+ }
+
+ if(optind != argc - 1)
+ usage();
+
+ switch(format) {
+ default:
+ fprintf(stderr, "fdformat: bad floppy size: %dK\n", format);
+ exit(2);
+ case -1: suffix = ""; break;
+ case 360: suffix = ".360"; break;
+ case 720: suffix = ".720"; break;
+ case 800: suffix = ".800"; break;
+ case 820: suffix = ".820"; break;
+ case 1200: suffix = ".1200"; break;
+ case 1440: suffix = ".1440"; break;
+ case 1480: suffix = ".1480"; break;
+ case 1720: suffix = ".1720"; break;
+ }
+
+ devname = makename(argv[optind], suffix);
+
+ if((fd = open(devname, O_RDWR)) < 0) {
+ perror(devname);
+ exit(1);
+ }
+
+ if(ioctl(fd, FD_GTYPE, &fdt) < 0) {
+ fprintf(stderr, "fdformat: not a floppy disk: %s\n", devname);
+ exit(1);
+ }
+
+ switch(rate) {
+ case -1: break;
+ case 250: fdt.trans = FDC_250KBPS; break;
+ case 300: fdt.trans = FDC_300KBPS; break;
+ case 500: fdt.trans = FDC_500KBPS; break;
+ default:
+ fprintf(stderr, "fdformat: invalid transfer rate: %d\n", rate);
+ exit(2);
+ }
+
+ if (cyls >= 0) fdt.tracks = cyls;
+ if (secs >= 0) fdt.sectrac = secs;
+ if (fdt.sectrac > FD_MAX_NSEC) {
+ fprintf(stderr, "fdformat: too many sectors per track, max value is %d\n", FD_MAX_NSEC);
+ exit(2);
+ }
+ if (heads >= 0) fdt.heads = heads;
+ if (gaplen >= 0) fdt.f_gap = gaplen;
+ if (secsize >= 0) fdt.secsize = secsize;
+ if (steps >= 0) fdt.steptrac = steps;
+ if (intleave >= 0) fdt.f_inter = intleave;
+
+ bytes_per_track = fdt.sectrac * (1<<fdt.secsize) * 128;
+ tracks_per_dot = fdt.tracks * fdt.heads / 40;
+
+ if (verify_only) {
+ if(!quiet)
+ printf("Verify %dK floppy `%s'.\n",
+ fdt.tracks * fdt.heads * bytes_per_track / 1024,
+ devname);
+ }
+ else if(!quiet) {
+ printf("Format %dK floppy `%s'? (y/n): ",
+ fdt.tracks * fdt.heads * bytes_per_track / 1024,
+ devname);
+ if(! yes ()) {
+ printf("Not confirmed.\n");
+ return 0;
+ }
+ }
+
+ /*
+ * Formatting.
+ */
+ if(!quiet) {
+ printf("Processing ----------------------------------------\r");
+ printf("Processing ");
+ fflush(stdout);
+ }
+
+ error = errs = 0;
+
+ for (track = 0; track < fdt.tracks * fdt.heads; track++) {
+ if (!verify_only) {
+ format_track(fd, track / fdt.heads, fdt.sectrac,
+ track % fdt.heads, fdt.trans, fdt.f_gap,
+ fdt.secsize, fill, fdt.f_inter);
+ if(!quiet && !((track + 1) % tracks_per_dot)) {
+ putchar('F');
+ fflush(stdout);
+ }
+ }
+ if (verify) {
+ if (verify_track(fd, track, bytes_per_track) < 0)
+ error = errs = 1;
+ if(!quiet && !((track + 1) % tracks_per_dot)) {
+ if (!verify_only)
+ putchar('\b');
+ if (error) {
+ putchar('E');
+ error = 0;
+ }
+ else
+ putchar('V');
+ fflush(stdout);
+ }
+ }
+ }
+ if(!quiet)
+ printf(" done.\n");
+
+ return errs;
+}
+/*
+ * Local Variables:
+ * c-indent-level: 8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * c-brace-offset: -8
+ * c-brace-imaginary-offset: 0
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c++-hanging-braces: 1
+ * c++-access-specifier-offset: -8
+ * c++-empty-arglist-indent: 8
+ * c++-friend-offset: 0
+ * End:
+ */
diff --git a/usr.sbin/fdwrite/Makefile b/usr.sbin/fdwrite/Makefile
new file mode 100644
index 0000000..23c22d8
--- /dev/null
+++ b/usr.sbin/fdwrite/Makefile
@@ -0,0 +1,16 @@
+#
+# ----------------------------------------------------------------------------
+# "THE BEER-WARE LICENSE" (Revision 42):
+# <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+# can do whatever you want with this stuff. If we meet some day, and you think
+# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+# ----------------------------------------------------------------------------
+#
+# $Id$
+#
+#
+
+PROG = fdwrite
+CFLAGS+= -Wall -I${DESTDIR}/sys
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fdwrite/fdwrite.1 b/usr.sbin/fdwrite/fdwrite.1
new file mode 100644
index 0000000..a8f527f
--- /dev/null
+++ b/usr.sbin/fdwrite/fdwrite.1
@@ -0,0 +1,117 @@
+.\"
+.\" ----------------------------------------------------------------------------
+.\" "THE BEER-WARE LICENSE" (Revision 42):
+.\" <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+.\" can do whatever you want with this stuff. If we meet some day, and you think
+.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+.\" ----------------------------------------------------------------------------
+.\"
+.\" $Id$
+.\"
+.\"
+.Dd September 16, 1993
+.Os FreeBSD
+.Dt FDWRITE 1
+.Sh NAME
+.Nm fdwrite
+.Nd format and write floppy disks
+.Sh SYNOPSIS
+.Nm fdwrite
+.Bq Fl v
+.Bq Fl f Ar inputfile
+.Bq Fl d Ar device
+.Sh DESCRIPTION
+.Nm Fdwrite
+formats and writes one and more floppy disks.
+Any floppy disk device capable of formatting can be used.
+
+.Nm Fdwrite
+will ask the user
+.Pq on /dev/tty
+to insert a new floppy and press return.
+The device will then be opened, and queried for it's paramters,
+then each track will be formatted, written with data from the
+.Ar inputfile ,
+read back and compared.
+When the floppy disk if filled, the process is repeated, with the next disk.
+This continues until the program is interrupted or EOF is encountered on the
+.Ar inputfile .
+
+The options are as follows:
+.Bl -tag -width 10n -offset indent
+.It Fl v
+toggles verbosity on stdout.
+Default is ``on''.
+After
+.Ar device
+is opened first time the format will be printed.
+During operation progress will be reported with the number of tracks
+remaining on the current floppy disk, and the letters I, Z, F, W,
+R and C, which indicates completion of Input, Zero-fill, Format
+Write, Read and Compare of current track respectively.
+.It Fl f Ar inputfile
+Input file to read. If none is given, stdin is assumed.
+.It Fl d Ar device
+The name of the floppy device to write to. Default is ``/dev/rfd0''.
+.El
+
+.Nm Fdwrite
+actually closes the
+.Ar device
+while it waits for the user to press return,
+it is thus quite possible to use the drive for other purposes at this
+time and later resume writing with the next floppy.
+
+The parameters returned from
+.Ar device
+are used for formatting.
+If custom formatting is needed, please use
+.Xr fdformat 1
+instead.
+
+.Sh EXAMPLE
+.Nm Fdwrite
+was planned as a tool to make life easier when writing a set of floppies,
+one such use could be to write a tar-archive:
+
+.ce 1
+tar cf - . | gzip -9 | fdwrite -d /dev/rfd0.1720 -v
+
+The main difference from using
+.Xr tar 1 's
+multivolume facility is of course the formatting of the floppies, which
+here is done on the fly,
+thus reducing the amount of work for the floppy-jockey.
+
+.Sh SEE ALSO
+.Xr fdformat 1 .
+.Sh HISTORY
+.Nm Fdwrite
+was written while waiting for ``make world'' to complete.
+Some of the code was taken from
+.Xr fdformat 1 .
+.Sh AUTHOR
+The program has been contributed by
+Poul-Henning Kamp <phk@login.dknet.dk>
+.Sh BUGS
+Diagnostics are less than complete at present.
+
+If a floppy is sick, and the
+.Ar inputfile
+is seekable, it should ask the user to frisbee the disk, insert
+another, and rewind to the right spot and continue.
+
+This concept could be extended to cover non-seekable input also
+by employing a temporary file .
+
+An option (defaulting to zero) should allow the user to ask for
+retries in case of failure.
+
+At present a suitable tool for reading back a multivolume set
+of floppies is missing.
+Programs like
+.Xr tar 1
+for instance, will do the job, if the data has not been compressed.
+One can always trust
+.Xr dd 1
+to help out in this situation of course
diff --git a/usr.sbin/fdwrite/fdwrite.c b/usr.sbin/fdwrite/fdwrite.c
new file mode 100644
index 0000000..8e3e914
--- /dev/null
+++ b/usr.sbin/fdwrite/fdwrite.c
@@ -0,0 +1,208 @@
+/*
+ * ----------------------------------------------------------------------------
+ * "THE BEER-WARE LICENSE" (Revision 42):
+ * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you
+ * can do whatever you want with this stuff. If we meet some day, and you think
+ * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
+ * ----------------------------------------------------------------------------
+ *
+ * $Id$
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include <errno.h>
+#include <machine/ioctl_fd.h>
+#include <i386/isa/fdreg.h> /* XXX should be in <machine> dir */
+
+int
+format_track(int fd, int cyl, int secs, int head, int rate,
+ int gaplen, int secsize, int fill,int interleave)
+{
+ struct fd_formb f;
+ register int i,j;
+ int il[100];
+
+ memset(il,0,sizeof il);
+ for(j = 0, i = 1; i <= secs; i++) {
+ while(il[(j%secs)+1]) j++;
+ il[(j%secs)+1] = i;
+ j += interleave;
+ }
+
+ f.format_version = FD_FORMAT_VERSION;
+ f.head = head;
+ f.cyl = cyl;
+ f.transfer_rate = rate;
+
+ f.fd_formb_secshift = secsize;
+ f.fd_formb_nsecs = secs;
+ f.fd_formb_gaplen = gaplen;
+ f.fd_formb_fillbyte = fill;
+ for(i = 0; i < secs; i++) {
+ f.fd_formb_cylno(i) = cyl;
+ f.fd_formb_headno(i) = head;
+ f.fd_formb_secno(i) = il[i+1];
+ f.fd_formb_secsize(i) = secsize;
+ }
+ return ioctl(fd, FD_FORM, (caddr_t)&f);
+}
+
+static void
+usage ()
+{
+ printf("Usage:\n\tfdwrite [-v] [-f inputfile] [-d device]\n");
+ exit(2);
+}
+
+int
+main(int argc, char **argv)
+{
+ int inputfd = -1, c, fdn = 0, i,j,fd;
+ int bpt, verbose=1, nbytes=0, track;
+ char *device= "/dev/rfd0", *trackbuf = 0,*vrfybuf = 0;
+ struct fd_type fdt;
+ FILE *tty;
+
+ setbuf(stdout,0);
+ while((c = getopt(argc, argv, "d:s:f:v")) != -1)
+ switch(c) {
+ case 'd': /* Which drive */
+ device = optarg;
+ break;
+
+ case 'f': /* input file */
+ if (inputfd >= 0)
+ close(inputfd);
+ inputfd = open(optarg,O_RDONLY);
+ if (inputfd < 0) {
+ perror(optarg);
+ exit(1);
+ }
+ break;
+
+ case 'v': /* Toggle verbosity */
+ verbose = !verbose;
+ break;
+
+ case '?': default:
+ usage();
+ }
+
+ if (inputfd < 0)
+ inputfd = 0;
+
+ if(optind < argc)
+ usage();
+
+ tty = fopen("/dev/tty","r+");
+ if(!tty) {
+ perror("/dev/tty");
+ exit(1);
+ }
+ setbuf(tty,0);
+
+ for(j=1;j > 0;) {
+ fdn++;
+ fprintf(tty,
+ "Please insert floppy #%d in drive %s and press return >",
+ fdn,device);
+ while(1) {
+ i = getc(tty);
+ if(i == '\n') break;
+ }
+
+ if((fd = open(device, O_RDWR)) < 0) {
+ perror(device);
+ exit(1);
+ }
+
+ if(ioctl(fd, FD_GTYPE, &fdt) < 0) {
+ fprintf(stderr, "fdformat: not a floppy disk: %s\n", device);
+ exit(1);
+ }
+
+ bpt = fdt.sectrac * (1<<fdt.secsize) * 128;
+ if(!trackbuf) {
+ trackbuf = malloc(bpt);
+ if(!trackbuf) { perror("malloc"); exit(1); }
+ }
+ if(!vrfybuf) {
+ vrfybuf = malloc(bpt);
+ if(!vrfybuf) { perror("malloc"); exit(1); }
+ }
+
+ if(fdn == 1) {
+ if(verbose) {
+ printf("Format: %d cylinders, %d heads, %d sectors, %d bytes = %dkb\n",
+ fdt.tracks,fdt.heads,fdt.sectrac,(1<<fdt.secsize) * 128,
+ fdt.tracks*bpt*fdt.heads/1024);
+
+ }
+ memset(trackbuf,0,bpt);
+ for(j=0;inputfd >= 0 && j<bpt;j+=i) {
+ if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
+ close(inputfd);
+ inputfd = -1;
+ break;
+ }
+ nbytes += i;
+ }
+ }
+ for (track = 0; track < fdt.tracks * fdt.heads; track++) {
+ if(verbose) printf("\r%3d ",fdt.tracks * fdt.heads-track);
+ if(verbose) putc((j ? 'I':'Z'),stdout);
+ format_track(fd, track / fdt.heads, fdt.sectrac, track % fdt.heads,
+ fdt.trans, fdt.f_gap, fdt.secsize, 0xe6,
+ fdt.f_inter);
+ if(verbose) putc('F',stdout);
+
+ if (lseek (fd, (long) track*bpt, 0) < 0) {
+ perror("lseek");
+ exit (1);
+ }
+ if (write (fd, trackbuf, bpt) != bpt) {
+ perror("write");
+ exit (1);
+ }
+ if(verbose) putc('W',stdout);
+
+ if (lseek (fd, (long) track*bpt, 0) < 0) {
+ perror("lseek");
+ exit (1);
+ }
+ if (read (fd, vrfybuf, bpt) != bpt) {
+ perror("read");
+ exit (1);
+ }
+ if(verbose) putc('R',stdout);
+
+ if (memcmp(trackbuf,vrfybuf,bpt)) {
+ perror("compare");
+ exit (1);
+ }
+ if(verbose) putc('C',stdout);
+
+ memset(trackbuf,0,bpt);
+ for(j=0;inputfd >= 0 && j<bpt;j+=i) {
+ if(!(i = read(inputfd,trackbuf+j,bpt-j))) {
+ close(inputfd);
+ inputfd = -1;
+ break;
+ }
+ nbytes += i;
+ }
+ }
+ close(fd);
+ putc('\r',stdout);
+ }
+ if(verbose)
+ printf("%d bytes on %d flopp%s\n",nbytes,fdn,fdn==1?"y":"ies");
+ exit(0);
+}
diff --git a/usr.sbin/inetd/Makefile b/usr.sbin/inetd/Makefile
new file mode 100644
index 0000000..0eecd6b
--- /dev/null
+++ b/usr.sbin/inetd/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= inetd
+MAN8= inetd.8
+MLINKS= inetd.8 inetd.conf.5
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/inetd/inetd.8 b/usr.sbin/inetd/inetd.8
new file mode 100644
index 0000000..cfb8b86
--- /dev/null
+++ b/usr.sbin/inetd/inetd.8
@@ -0,0 +1,425 @@
+.\" Copyright (c) 1985, 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: @(#)inetd.8 8.3 (Berkeley) 4/13/94
+.\" $Id$
+.\"
+.Dd April 13, 1994
+.Dt INETD 8
+.Os BSD 4.4
+.Sh NAME
+.Nm inetd
+.Nd internet
+.Dq super-server
+.Sh SYNOPSIS
+.Nm inetd
+.Op Fl d
+.Op Fl l
+.Op Fl R Ar rate
+.Op Ar configuration file
+.Sh DESCRIPTION
+The
+.Nm inetd
+program
+should be run at boot time by
+.Pa /etc/rc
+(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.
+The server program is invoked with the service socket
+as its standard input, output and error descriptors.
+After the program is
+finished,
+.Nm inetd
+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 options available for
+.Nm inetd:
+.Bl -tag -width Ds
+.It Fl d
+Turns on debugging.
+.It Fl l
+Turns on logging.
+.It Fl R Ar rate
+Specifies the maximum number of times a service can be invoked
+in one minute; the default is 1000.
+.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
+user
+server program
+server program arguments
+.Ed
+.Pp
+To specify a
+.Em Sun-RPC
+based service, the entry would contain these fields:
+.Pp
+.Bd -unfilled -offset indent -compact
+service name/version
+socket type
+rpc/protocol
+user
+server program
+server program arguments
+.Ed
+.Pp
+There are two types of services that
+.Nm inetd
+can start: standard and TCPMUX.
+A standard service has a well-known port assigned to it;
+it may be a service that implements an official Internet standard or is a
+BSD-specific service.
+As described in
+.Tn RFC 1078 ,
+TCPMUX services are nonstandard services that do not have a
+well-known port assigned to them.
+They are invoked from
+.Nm inetd
+when a program connects to the
+.Dq tcpmux
+well-known port and specifies
+the service name.
+This feature is useful for adding locally-developed servers.
+.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 .
+For TCPMUX services, the value of the
+.Em service-name
+field consists of the string
+.Dq tcpmux
+followed by a slash and the
+locally-chosen service name.
+The service names listed in
+.Pa /etc/services
+and the name
+.Dq help
+are reserved.
+Try to choose unique names for your TCPMUX services by prefixing them with
+your organization's name and suffixing them with a version number.
+.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.
+TCPMUX services must use
+.Dq stream .
+.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.
+TCPMUX services must use
+.Dq tcp .
+.Pp
+The
+.Em wait/nowait
+entry specifies whether the server that is invoked by inetd will take over
+the socket associated with the service access point, and thus whether
+.Nm inetd
+should wait for the server to exit before listening for new service
+requests.
+Datagram servers must use
+.Dq wait ,
+as they are always invoked with the original datagram socket bound
+to the specified service address.
+These servers must read at least one datagram from the socket
+before exiting.
+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;
+it should read one datagram from the socket and create a new socket
+connected to the peer.
+It should fork, and the parent should then exit
+to allow
+.Nm inetd
+to check for new service requests to spawn new servers.
+Datagram servers which process all incoming datagrams
+on a socket and eventually time out are said to be
+.Dq single-threaded .
+.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 example of a multi-threaded datagram server.
+.Pp
+Servers using stream sockets generally are multi-threaded and
+use the
+.Dq nowait
+entry.
+Connection requests for these services are accepted by
+.Nm inetd ,
+and the server is given only the newly-accepted socket connected
+to a client of the service.
+Most stream-based services operate in this manner.
+Stream-based servers that use
+.Dq wait
+are started with the listening service socket, and must accept
+at least one connection request before exiting.
+Such a server would normally accept and process incoming connection
+requests until a timeout.
+TCPMUX services must use
+.Dq nowait .
+.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.
+.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
+The
+.Nm inetd
+program
+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
+When given the
+.Fl l
+option
+.Nm Inetd
+will log an entry to syslog each time an
+.Xr accept 2
+is made, which notes the
+service selected and the IP-number of the remote requestor.
+.Pp
+The
+.Nm inetd
+program
+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.
+.Sh TCPMUX
+.Pp
+.Tn RFC 1078
+describes the TCPMUX protocol:
+``A TCP client connects to a foreign host on TCP port 1. It sends the
+service name followed by a carriage-return line-feed <CRLF>. The
+service name is never case sensitive. The server replies with a
+single character indicating positive (+) or negative (\-)
+acknowledgment, immediately followed by an optional message of
+explanation, terminated with a <CRLF>. If the reply was positive,
+the selected protocol begins; otherwise the connection is closed.''
+The program is passed the TCP connection as file descriptors 0 and 1.
+.Pp
+If the TCPMUX service name begins with a ``+'',
+.Nm inetd
+returns the positive reply for the program.
+This allows you to invoke programs that use stdin/stdout
+without putting any special server code in them.
+.Pp
+The special service name
+.Dq help
+causes
+.Nm inetd
+to list TCPMUX services in
+.Pa inetd.conf .
+.Sh "EXAMPLES"
+.Pp
+Here are several example service entries for the various types of services:
+.Bd -literal
+ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l
+ntalk dgram udp wait root /usr/libexec/ntalkd ntalkd
+tcpmux/+date stream tcp nowait guest /bin/date date
+tcpmux/phonebook stream tcp nowait guest /usr/local/bin/phonebook phonebook
+rstatd/1-3 dgram rpc/udp wait root /usr/libexec/rpc.rstatd rpc.rstatd
+.Ed
+.Sh "ERROR MESSAGES"
+The
+.Nm inetd
+server
+logs error messages using
+.Xr syslog 3 .
+Important error messages and their explanations are:
+.Bd -literal
+\fIservice\fP/\fIprotocol\fP server failing (looping), service terminated.
+.Ed
+The number of requests for the specified service in the past minute
+exceeded the limit. The limit exists to prevent a broken program
+or a malicious user from swamping the system.
+This message may occur for several reasons:
+1) there are lots of hosts requesting the service within a short time period,
+2) a 'broken' client program is requesting the service too frequently,
+3) a malicious user is running a program to invoke the service in
+a 'denial of service' attack, or
+4) the invoked service program has an error that causes clients
+to retry quickly.
+Use the
+.Op Fl R
+option,
+as described above, to change the rate limit.
+Once the limit is reached, the service will be
+reenabled automatically in 10 minutes.
+.sp
+.Bd -literal
+\fIservice\fP/\fIprotocol\fP: No such user '\fIuser\fP', service ignored
+\fIservice\fP/\fIprotocol\fP: getpwnam: \fIuser\fP: No such user
+.Ed
+No entry for
+.Em user
+exists in the
+.Pa passwd
+file. The first message
+occurs when
+.Nm inetd
+(re)reads the configuration file. The second message occurs when the
+service is invoked.
+.sp
+.Bd -literal
+\fIservice\fP: can't set uid \fInumber\fP
+\fIservice\fP: can't set gid \fInumber\fP
+.Ed
+The user or group ID for the entry's
+.Em user
+is invalid.
+.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 ,
+.Xr portmap 8 ,
+.Xr rpc 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
+TCPMUX is based on code and documentation by Mark Lottor.
+Support for
+.Em Sun-RPC
+based services is modelled after that
+provided by
+.Em SunOS 4.1 .
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
new file mode 100644
index 0000000..e3e79c6
--- /dev/null
+++ b/usr.sbin/inetd/inetd.c
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (c) 1983, 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
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/* from: @(#)inetd.c 8.4 (Berkeley) 4/13/94"; */
+static char RCSid[] = "$Id";
+#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 or must
+ * name a tcpmux service
+ * socket type stream/dgram/raw/rdm/seqpacket
+ * protocol must be in /etc/protocols
+ * wait/nowait single-threaded/multi-threaded
+ * user user to run daemon as
+ * server program full path name
+ * server program arguments maximum of MAXARGS (20)
+ *
+ * TCP services without official port numbers are handled with the
+ * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
+ * requests. When a connection is made from a foreign host, the service
+ * requested is passed to tcpmux, which looks it up in the servtab list
+ * and returns the proper entry for the service. Tcpmux returns a
+ * negative reply if the service doesn't exist, otherwise the invoked
+ * server is expected to return the positive reply if the service type in
+ * inetd.conf file has the prefix "tcpmux/". If the service type has the
+ * prefix "tcpmux/+", tcpmux will return the positive reply for the
+ * process; this is for compatibility with older server code, and also
+ * allows you to invoke programs that use stdin/stdout without putting any
+ * special server code in them. Services that use tcpmux are "nowait"
+ * because they do not have a well-known port and hence cannot listen
+ * for new requests.
+ *
+ * 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 single-threaded/multi-threaded
+ * user user to run daemon as
+ * server program full path name
+ * server program arguments maximum of MAXARGS
+ *
+ * Comment lines are indicated by a `#' in column 1.
+ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <rpc/rpc.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#define TOOMANY 256 /* 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))
+
+
+int debug = 0;
+int log = 0;
+int nsock, maxsock;
+fd_set allsock;
+int options;
+int timingout;
+int toomany = TOOMANY;
+struct servent *sp;
+struct rpcent *rpc;
+
+struct servtab {
+ char *se_service; /* name of service */
+ int se_socktype; /* type of socket to use */
+ char *se_proto; /* protocol used */
+ short se_wait; /* single threaded server */
+ short se_checked; /* looked at during merge */
+ char *se_user; /* user 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 */
+ int se_type; /* type */
+ struct sockaddr_in se_ctrladdr;/* bound address */
+ int se_rpc; /* ==1 if RPC service */
+ int se_rpc_prog; /* RPC program number */
+ u_int se_rpc_lowvers; /* RPC low version */
+ u_int se_rpc_highvers; /* RPC high version */
+ int se_count; /* number started since se_time */
+ struct timeval se_time; /* start of se_count */
+ struct servtab *se_next;
+} *servtab;
+
+#define NORM_TYPE 0
+#define MUX_TYPE 1
+#define MUXPLUS_TYPE 2
+#define ISMUX(sep) (((sep)->se_type == MUX_TYPE) || \
+ ((sep)->se_type == MUXPLUS_TYPE))
+#define ISMUXPLUS(sep) ((sep)->se_type == MUXPLUS_TYPE)
+
+
+void chargen_dg __P((int, struct servtab *));
+void chargen_stream __P((int, struct servtab *));
+void close_sep __P((struct servtab *));
+void config __P((int));
+void daytime_dg __P((int, struct servtab *));
+void daytime_stream __P((int, struct servtab *));
+void discard_dg __P((int, struct servtab *));
+void discard_stream __P((int, struct servtab *));
+void echo_dg __P((int, struct servtab *));
+void echo_stream __P((int, struct servtab *));
+void endconfig __P((void));
+struct servtab *enter __P((struct servtab *));
+void freeconfig __P((struct servtab *));
+struct servtab *getconfigent __P((void));
+void machtime_dg __P((int, struct servtab *));
+void machtime_stream __P((int, struct servtab *));
+char *newstr __P((char *));
+char *nextline __P((FILE *));
+void print_service __P((char *, struct servtab *));
+void reapchild __P((int));
+void retry __P((int));
+int setconfig __P((void));
+void setup __P((struct servtab *));
+char *sskip __P((char **));
+char *skip __P((char **));
+struct servtab *tcpmux __P((int));
+
+void unregisterrpc __P((register struct servtab *sep));
+
+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 */
+ void (*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 1970 */
+ { "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 },
+
+ { "tcpmux", SOCK_STREAM, 1, 0, (void (*)())tcpmux },
+
+ { NULL }
+};
+
+#define NUMINT (sizeof(intab) / sizeof(struct inent))
+char *CONFIG = _PATH_INETDCONF;
+char **Argv;
+char *LastArg;
+
+int
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ struct servtab *sep;
+ struct passwd *pwd;
+ struct sigvec sv;
+ int tmpint, ch, dofork;
+ pid_t pid;
+ char buf[50];
+ struct sockaddr_in peer;
+ int i;
+
+ Argv = argv;
+ if (envp == 0 || *envp == 0)
+ envp = argv;
+ while (*envp)
+ envp++;
+ LastArg = envp[-1] + strlen(envp[-1]);
+
+ openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
+
+ while ((ch = getopt(argc, argv, "dlR:")) != EOF)
+ switch(ch) {
+ case 'd':
+ debug = 1;
+ options |= SO_DEBUG;
+ break;
+ case 'l':
+ log = 1;
+ break;
+ case 'R': { /* invocation rate */
+ char *p;
+
+ tmpint = strtol(optarg, &p, 0);
+ if (tmpint < 1 || *p)
+ syslog(LOG_ERR,
+ "-R %s: bad value for service invocation rate",
+ optarg);
+ else
+ toomany = tmpint;
+ break;
+ }
+ case '?':
+ default:
+ syslog(LOG_ERR,
+ "usage: inetd [-dl] [-R rate] [conf-file]");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ CONFIG = argv[0];
+ if (debug == 0) {
+ daemon(0, 0);
+ }
+ memset(&sv, 0, sizeof(sv));
+ sv.sv_mask = SIGBLOCK;
+ sv.sv_handler = retry;
+ sigvec(SIGALRM, &sv, (struct sigvec *)0);
+ config(SIGHUP);
+ sv.sv_handler = config;
+ sigvec(SIGHUP, &sv, (struct sigvec *)0);
+ sv.sv_handler = reapchild;
+ sigvec(SIGCHLD, &sv, (struct sigvec *)0);
+
+ {
+ /* space for daemons to overwrite environment for ps */
+#define DUMMYSIZE 100
+ char dummy[DUMMYSIZE];
+
+ (void)memset(dummy, 'x', sizeof(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");
+ 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)
+ syslog(LOG_WARNING,
+ "accept (for %s): %m",
+ sep->se_service);
+ continue;
+ }
+ if(log) {
+ i = sizeof peer;
+ if(getpeername(ctrl, (struct sockaddr *)
+ &peer, &i)) {
+ syslog(LOG_WARNING,
+ "getpeername(for %s): %m",
+ sep->se_service);
+ continue;
+ }
+ syslog(LOG_INFO,"%s from %s",
+ sep->se_service,
+ inet_ntoa(peer.sin_addr));
+ }
+ /*
+ * Call tcpmux to find the real service to exec.
+ */
+ if (sep->se_bi &&
+ sep->se_bi->bi_fn == (void (*)()) tcpmux) {
+ sep = tcpmux(ctrl);
+ if (sep == NULL) {
+ close(ctrl);
+ 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 >= toomany) {
+ 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",
+ sep->se_service, sep->se_proto);
+ close_sep(sep);
+ sigsetmask(0L);
+ if (!timingout) {
+ timingout = 1;
+ alarm(RETRYTIME);
+ }
+ continue;
+ }
+ }
+ pid = fork();
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ if (!sep->se_wait &&
+ sep->se_socktype == SOCK_STREAM)
+ close(ctrl);
+ sigsetmask(0L);
+ sleep(1);
+ continue;
+ }
+ if (pid && sep->se_wait) {
+ sep->se_wait = pid;
+ if (sep->se_fd >= 0) {
+ FD_CLR(sep->se_fd, &allsock);
+ nsock--;
+ }
+ }
+ sigsetmask(0L);
+ if (pid == 0) {
+ if (debug && dofork)
+ setsid();
+ if (dofork) {
+ if (debug)
+ fprintf(stderr, "+ Closing from %d\n",
+ maxsock);
+ for (tmpint = maxsock; tmpint > 2; tmpint--)
+ if (tmpint != ctrl)
+ close(tmpint);
+ }
+ if (sep->se_bi)
+ (*sep->se_bi->bi_fn)(ctrl, sep);
+ else {
+ if (debug)
+ fprintf(stderr, "%d execl %s\n",
+ getpid(), sep->se_server);
+ dup2(ctrl, 0);
+ close(ctrl);
+ dup2(0, 1);
+ dup2(0, 2);
+ if ((pwd = getpwnam(sep->se_user)) == NULL) {
+ syslog(LOG_ERR,
+ "%s/%s: %s: No such user",
+ sep->se_service, sep->se_proto,
+ sep->se_user);
+ if (sep->se_socktype != SOCK_STREAM)
+ recv(0, buf, sizeof (buf), 0);
+ _exit(1);
+ }
+ if (pwd->pw_uid) {
+ if (setgid(pwd->pw_gid) < 0) {
+ syslog(LOG_ERR,
+ "%s: can't set gid %d: %m",
+ sep->se_service, pwd->pw_gid);
+ _exit(1);
+ }
+ (void) initgroups(pwd->pw_name,
+ pwd->pw_gid);
+ if (setuid(pwd->pw_uid) < 0) {
+ syslog(LOG_ERR,
+ "%s: can't set uid %d: %m",
+ sep->se_service, pwd->pw_uid);
+ _exit(1);
+ }
+ }
+ execv(sep->se_server, sep->se_argv);
+ if (sep->se_socktype != SOCK_STREAM)
+ recv(0, buf, sizeof (buf), 0);
+ syslog(LOG_ERR,
+ "cannot execute %s: %m", sep->se_server);
+ _exit(1);
+ }
+ }
+ if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
+ close(ctrl);
+ }
+ }
+}
+
+void
+reapchild(signo)
+ int signo;
+{
+ int status;
+ pid_t pid;
+ struct servtab *sep;
+
+ for (;;) {
+ pid = wait3(&status, WNOHANG, (struct rusage *)0);
+ if (pid <= 0)
+ break;
+ if (debug)
+ fprintf(stderr, "%d reaped, status %#x\n",
+ pid, status);
+ for (sep = servtab; sep; sep = sep->se_next)
+ if (sep->se_wait == pid) {
+ if (status)
+ syslog(LOG_WARNING,
+ "%s: exit status 0x%x",
+ sep->se_server, status);
+ if (debug)
+ fprintf(stderr, "restored %s, fd %d\n",
+ sep->se_service, sep->se_fd);
+ FD_SET(sep->se_fd, &allsock);
+ nsock++;
+ sep->se_wait = 1;
+ }
+ }
+}
+
+void
+config(signo)
+ int signo;
+{
+ struct servtab *sep, *cp, **sepp;
+ struct passwd *pwd;
+ long omask;
+
+ if (!setconfig()) {
+ syslog(LOG_ERR, "%s: %m", CONFIG);
+ return;
+ }
+ for (sep = servtab; sep; sep = sep->se_next)
+ sep->se_checked = 0;
+ while (cp = getconfigent()) {
+ if ((pwd = getpwnam(cp->se_user)) == NULL) {
+ syslog(LOG_ERR,
+ "%s/%s: No such user '%s', service ignored",
+ cp->se_service, cp->se_proto, cp->se_user);
+ continue;
+ }
+ 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;
+
+ 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;
+#define SWAP(a, b) { char *c = a; a = b; b = c; }
+ if (cp->se_user)
+ SWAP(sep->se_user, cp->se_user);
+ if (cp->se_server)
+ SWAP(sep->se_server, cp->se_server);
+ for (i = 0; i < MAXARGV; i++)
+ SWAP(sep->se_argv[i], cp->se_argv[i]);
+ sigsetmask(omask);
+ freeconfig(cp);
+ if (debug)
+ print_service("REDO", sep);
+ } else {
+ sep = enter(cp);
+ if (debug)
+ print_service("ADD ", sep);
+ }
+ sep->se_checked = 1;
+ if (ISMUX(sep)) {
+ sep->se_fd = -1;
+ continue;
+ }
+ if (!sep->se_rpc) {
+ sp = getservbyname(sep->se_service, sep->se_proto);
+ if (sp == 0) {
+ syslog(LOG_ERR, "%s/%s: unknown service",
+ sep->se_service, sep->se_proto);
+ sep->se_checked = 0;
+ continue;
+ }
+ if (sp->s_port != sep->se_ctrladdr.sin_port) {
+ sep->se_ctrladdr.sin_family = AF_INET;
+ sep->se_ctrladdr.sin_port = sp->s_port;
+ if (sep->se_fd >= 0)
+ close_sep(sep);
+ }
+ } else {
+ rpc = getrpcbyname(sep->se_service);
+ if (rpc == 0) {
+ syslog(LOG_ERR, "%s/%s unknown RPC service.",
+ sep->se_service, sep->se_proto);
+ if (sep->se_fd != -1)
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ continue;
+ }
+ if (rpc->r_number != sep->se_rpc_prog) {
+ if (sep->se_rpc_prog)
+ unregisterrpc(sep);
+ sep->se_rpc_prog = rpc->r_number;
+ if (sep->se_fd != -1)
+ (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 >= 0)
+ close_sep(sep);
+ if (debug)
+ print_service("FREE", sep);
+ if (sep->se_rpc && sep->se_rpc_prog > 0)
+ unregisterrpc(sep);
+ freeconfig(sep);
+ free((char *)sep);
+ }
+ (void) sigsetmask(omask);
+}
+
+void
+unregisterrpc(sep)
+ struct servtab *sep;
+{
+ int i;
+ struct servtab *sepp;
+ long omask;
+
+ omask = sigblock(SIGBLOCK);
+ for (sepp = servtab; sepp; sepp = sepp->se_next) {
+ if (sepp == sep)
+ continue;
+ if (sep->se_checked == 0 ||
+ !sepp->se_rpc ||
+ sep->se_rpc_prog != sepp->se_rpc_prog)
+ continue;
+ return;
+ }
+ if (debug)
+ print_service("UNREG", sep);
+ for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
+ pmap_unset(sep->se_rpc_prog, i);
+ if (sep->se_fd != -1)
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ (void) sigsetmask(omask);
+}
+
+void
+retry(signo)
+ int signo;
+{
+ struct servtab *sep;
+
+ timingout = 0;
+ for (sep = servtab; sep; sep = sep->se_next)
+ if (sep->se_fd == -1)
+ setup(sep);
+}
+
+void
+setup(sep)
+ struct servtab *sep;
+{
+ int on = 1;
+
+ if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
+ if (debug)
+ fprintf(stderr, "socket failed on %s/%s: %s\n",
+ sep->se_service, sep->se_proto,
+ strerror(errno));
+ 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, (struct sockaddr *)&sep->se_ctrladdr,
+ sizeof (sep->se_ctrladdr)) < 0) {
+ if (debug)
+ fprintf(stderr, "bind failed on %s/%s: %s\n",
+ sep->se_service, sep->se_proto,
+ strerror(errno));
+ 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_rpc) {
+ int i, len = sizeof(struct sockaddr);
+
+ if (getsockname(sep->se_fd,
+ (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
+ syslog(LOG_ERR, "%s/%s: getsockname: %m",
+ sep->se_service, sep->se_proto);
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ return;
+ }
+ if (debug)
+ print_service("REG ", sep);
+ for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
+ pmap_unset(sep->se_rpc_prog, i);
+ pmap_set(sep->se_rpc_prog, i,
+ (sep->se_socktype == SOCK_DGRAM)
+ ? IPPROTO_UDP : IPPROTO_TCP,
+ ntohs(sep->se_ctrladdr.sin_port));
+ }
+
+ }
+ 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 (debug) {
+ fprintf(stderr, "registered %s on %d\n",
+ sep->se_server, sep->se_fd);
+ }
+}
+
+/*
+ * Finish with a service and its socket.
+ */
+void
+close_sep(sep)
+ struct servtab *sep;
+{
+ if (sep->se_fd >= 0) {
+ nsock--;
+ FD_CLR(sep->se_fd, &allsock);
+ (void) close(sep->se_fd);
+ sep->se_fd = -1;
+ }
+ sep->se_count = 0;
+ /*
+ * Don't keep the pid of this running deamon: when reapchild()
+ * reaps this pid, it would erroneously increment nsock.
+ */
+ if (sep->se_wait > 1)
+ sep->se_wait = 1;
+}
+
+struct servtab *
+enter(cp)
+ struct servtab *cp;
+{
+ 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;
+ omask = sigblock(SIGBLOCK);
+ sep->se_next = servtab;
+ servtab = sep;
+ sigsetmask(omask);
+ return (sep);
+}
+
+FILE *fconfig = NULL;
+struct servtab serv;
+char line[LINE_MAX];
+
+int
+setconfig()
+{
+
+ if (fconfig != NULL) {
+ fseek(fconfig, 0L, SEEK_SET);
+ return (1);
+ }
+ fconfig = fopen(CONFIG, "r");
+ return (fconfig != NULL);
+}
+
+void
+endconfig()
+{
+ if (fconfig) {
+ (void) fclose(fconfig);
+ fconfig = NULL;
+ }
+}
+
+struct servtab *
+getconfigent()
+{
+ struct servtab *sep = &serv;
+ int argc;
+ char *cp, *arg;
+ char *versp;
+ static char TCPMUX_TOKEN[] = "tcpmux/";
+#define MUX_LEN (sizeof(TCPMUX_TOKEN)-1)
+
+more:
+ while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
+ ;
+ if (cp == NULL)
+ return ((struct servtab *)0);
+ /*
+ * clear the static buffer, since some fields (se_ctrladdr,
+ * for example) don't get initialized here.
+ */
+ memset((caddr_t)sep, 0, sizeof *sep);
+ arg = skip(&cp);
+ if (cp == NULL) {
+ /* got an empty line containing just blanks/tabs. */
+ goto more;
+ }
+ if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
+ char *c = arg + MUX_LEN;
+ if (*c == '+') {
+ sep->se_type = MUXPLUS_TYPE;
+ c++;
+ } else
+ sep->se_type = MUX_TYPE;
+ sep->se_service = newstr(c);
+ } else {
+ sep->se_service = newstr(arg);
+ sep->se_type = NORM_TYPE;
+ }
+ arg = sskip(&cp);
+ 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(sskip(&cp));
+ if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
+ sep->se_proto += 4;
+ sep->se_rpc = 1;
+ sep->se_rpc_prog = sep->se_rpc_lowvers =
+ sep->se_rpc_lowvers = 0;
+ sep->se_ctrladdr.sin_family = AF_INET;
+ sep->se_ctrladdr.sin_port = 0;
+ sep->se_ctrladdr.sin_addr.s_addr = htonl(INADDR_ANY);
+ if ((versp = rindex(sep->se_service, '/'))) {
+ *versp++ = '\0';
+ switch (sscanf(versp, "%d-%d",
+ &sep->se_rpc_lowvers,
+ &sep->se_rpc_highvers)) {
+ case 2:
+ break;
+ case 1:
+ sep->se_rpc_highvers =
+ sep->se_rpc_lowvers;
+ break;
+ default:
+ syslog(LOG_ERR,
+ "bad RPC version specifier; %s\n",
+ sep->se_service);
+ freeconfig(sep);
+ goto more;
+ }
+ }
+ else {
+ sep->se_rpc_lowvers =
+ sep->se_rpc_highvers = 1;
+ }
+ }
+ arg = sskip(&cp);
+ sep->se_wait = strcmp(arg, "wait") == 0;
+ if (ISMUX(sep)) {
+ /*
+ * Silently enforce "nowait" for TCPMUX services since
+ * they don't have an assigned port to listen on.
+ */
+ sep->se_wait = 0;
+
+ if (strcmp(sep->se_proto, "tcp")) {
+ syslog(LOG_ERR,
+ "%s: bad protocol for tcpmux service %s",
+ CONFIG, sep->se_service);
+ goto more;
+ }
+ if (sep->se_socktype != SOCK_STREAM) {
+ syslog(LOG_ERR,
+ "%s: bad socket type for tcpmux service %s",
+ CONFIG, sep->se_service);
+ goto more;
+ }
+ }
+ sep->se_user = newstr(sskip(&cp));
+ sep->se_server = newstr(sskip(&cp));
+ if (strcmp(sep->se_server, "internal") == 0) {
+ 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",
+ 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 (argc < MAXARGV)
+ sep->se_argv[argc++] = newstr(arg);
+ while (argc <= MAXARGV)
+ sep->se_argv[argc++] = NULL;
+ return (sep);
+}
+
+void
+freeconfig(cp)
+ 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);
+ if (cp->se_server)
+ free(cp->se_server);
+ for (i = 0; i < MAXARGV; i++)
+ if (cp->se_argv[i])
+ free(cp->se_argv[i]);
+}
+
+
+/*
+ * Safe skip - if skip returns null, log a syntax error in the
+ * configuration file and exit.
+ */
+char *
+sskip(cpp)
+ char **cpp;
+{
+ char *cp;
+
+ cp = skip(cpp);
+ if (cp == NULL) {
+ syslog(LOG_ERR, "%s: syntax error", CONFIG);
+ exit(-1);
+ }
+ return (cp);
+}
+
+char *
+skip(cpp)
+ char **cpp;
+{
+ char *cp = *cpp;
+ char *start;
+
+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 = strchr(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);
+}
+
+void
+setproctitle(a, s)
+ char *a;
+ int s;
+{
+ int size;
+ 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++ = ' ';
+}
+
+/*
+ * Internet services provided internally by inetd:
+ */
+#define BUFSIZE 8192
+
+/* ARGSUSED */
+void
+echo_stream(s, sep) /* Echo service -- echo data back */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[BUFSIZE];
+ int i;
+
+ setproctitle(sep->se_service, s);
+ while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
+ write(s, buffer, i) > 0)
+ ;
+ exit(0);
+}
+
+/* ARGSUSED */
+void
+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 */
+void
+discard_stream(s, sep) /* Discard service -- ignore data */
+ int s;
+ struct servtab *sep;
+{
+ int ret;
+ char buffer[BUFSIZE];
+
+ setproctitle(sep->se_service, s);
+ while (1) {
+ while ((ret = read(s, buffer, sizeof(buffer))) > 0)
+ ;
+ if (ret == 0 || errno != EINTR)
+ break;
+ }
+ exit(0);
+}
+
+/* ARGSUSED */
+void
+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;
+
+void
+initring()
+{
+ int i;
+
+ endring = ring;
+
+ for (i = 0; i <= 128; ++i)
+ if (isprint(i))
+ *endring++ = i;
+}
+
+/* ARGSUSED */
+void
+chargen_stream(s, sep) /* Character generator */
+ int s;
+ struct servtab *sep;
+{
+ int len;
+ char *rs, text[LINESIZ+2];
+
+ 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)
+ memmove(text, rs, LINESIZ);
+ else {
+ memmove(text, rs, len);
+ memmove(text + len, ring, LINESIZ - len);
+ }
+ if (++rs == endring)
+ rs = ring;
+ if (write(s, text, sizeof(text)) != sizeof(text))
+ break;
+ }
+ exit(0);
+}
+
+/* ARGSUSED */
+void
+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)
+ memmove(text, rs, LINESIZ);
+ else {
+ memmove(text, rs, len);
+ memmove(text + len, ring, 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) {
+ if (debug)
+ fprintf(stderr, "Unable to get time of day\n");
+ return (0L);
+ }
+#define OFFSET ((u_long)25567 * 24*60*60)
+ return (htonl((long)(tv.tv_sec + OFFSET)));
+#undef OFFSET
+}
+
+/* ARGSUSED */
+void
+machtime_stream(s, sep)
+ int s;
+ struct servtab *sep;
+{
+ long result;
+
+ result = machtime();
+ (void) write(s, (char *) &result, sizeof(result));
+}
+
+/* ARGSUSED */
+void
+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 */
+void
+daytime_stream(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t clock;
+
+ clock = time((time_t *) 0);
+
+ (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
+ (void) write(s, buffer, strlen(buffer));
+}
+
+/* ARGSUSED */
+void
+daytime_dg(s, sep) /* Return human-readable time of day */
+ int s;
+ struct servtab *sep;
+{
+ char buffer[256];
+ time_t 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
+ */
+void
+print_service(action, sep)
+ char *action;
+ struct servtab *sep;
+{
+ if(sep->se_rpc)
+ fprintf(stderr,
+ "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
+ action, sep->se_service, sep->se_proto,
+ sep->se_wait, sep->se_user, (int)sep->se_bi,
+ sep->se_server);
+ else
+ fprintf(stderr,
+ "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
+ action, sep->se_service, sep->se_proto,
+ sep->se_wait, sep->se_user, (int)sep->se_bi,
+ sep->se_server);
+}
+
+/*
+ * Based on TCPMUX.C by Mark K. Lottor November 1988
+ * sri-nic::ps:<mkl>tcpmux.c
+ */
+
+
+static int /* # of characters upto \r,\n or \0 */
+getline(fd, buf, len)
+ int fd;
+ char *buf;
+ int len;
+{
+ int count = 0, n;
+
+ do {
+ n = read(fd, buf, len-count);
+ if (n == 0)
+ return (count);
+ if (n < 0)
+ return (-1);
+ while (--n >= 0) {
+ if (*buf == '\r' || *buf == '\n' || *buf == '\0')
+ return (count);
+ count++;
+ buf++;
+ }
+ } while (count < len);
+ return (count);
+}
+
+#define MAX_SERV_LEN (256+2) /* 2 bytes for \r\n */
+
+#define strwrite(fd, buf) (void) write(fd, buf, sizeof(buf)-1)
+
+struct servtab *
+tcpmux(s)
+ int s;
+{
+ struct servtab *sep;
+ char service[MAX_SERV_LEN+1];
+ int len;
+
+ /* Get requested service name */
+ if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
+ strwrite(s, "-Error reading service name\r\n");
+ return (NULL);
+ }
+ service[len] = '\0';
+
+ if (debug)
+ fprintf(stderr, "tcpmux: someone wants %s\n", service);
+
+ /*
+ * Help is a required command, and lists available services,
+ * one per line.
+ */
+ if (!strcasecmp(service, "help")) {
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (!ISMUX(sep))
+ continue;
+ (void)write(s,sep->se_service,strlen(sep->se_service));
+ strwrite(s, "\r\n");
+ }
+ return (NULL);
+ }
+
+ /* Try matching a service in inetd.conf with the request */
+ for (sep = servtab; sep; sep = sep->se_next) {
+ if (!ISMUX(sep))
+ continue;
+ if (!strcasecmp(service, sep->se_service)) {
+ if (ISMUXPLUS(sep)) {
+ strwrite(s, "+Go\r\n");
+ }
+ return (sep);
+ }
+ }
+ strwrite(s, "-Service not available\r\n");
+ return (NULL);
+}
diff --git a/usr.sbin/inetd/pathnames.h b/usr.sbin/inetd/pathnames.h
new file mode 100644
index 0000000..e8ae3cd
--- /dev/null
+++ b/usr.sbin/inetd/pathnames.h
@@ -0,0 +1,38 @@
+/*
+ * 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_INETDCONF "/etc/inetd.conf"
diff --git a/usr.sbin/iostat/Makefile b/usr.sbin/iostat/Makefile
new file mode 100644
index 0000000..3c43296
--- /dev/null
+++ b/usr.sbin/iostat/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= iostat
+CFLAGS+=-I/sys -I${.CURDIR}/../../usr.bin/vmstat
+MAN8= 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 0000000..679dfc6
--- /dev/null
+++ b/usr.sbin/iostat/iostat.8
@@ -0,0 +1,142 @@
+.\" 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.
+.\"
+.\" @(#)iostat.8 8.1 (Berkeley) 6/6/93
+.\"
+.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 /kernel .
+.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 /kernel
+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 vmstat 1 ,
+.Xr pstat 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 0000000..a41cac4
--- /dev/null
+++ b/usr.sbin/iostat/iostat.c
@@ -0,0 +1,391 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94";
+#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 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/kbdcontrol/Makefile b/usr.sbin/kbdcontrol/Makefile
new file mode 100644
index 0000000..ad91cb0
--- /dev/null
+++ b/usr.sbin/kbdcontrol/Makefile
@@ -0,0 +1,6 @@
+PROG= kbdcontrol
+SRCS= kbdcontrol.c lex.l
+DPADD+= ${LIBL}
+LDADD+= -ll
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.1 b/usr.sbin/kbdcontrol/kbdcontrol.1
new file mode 100644
index 0000000..6451036
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.1
@@ -0,0 +1,77 @@
+.\"
+.\" kbdcontrol - a utility for manipulating the syscons keyboard driver section
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" @(#)kbdcontrol.1
+.\"
+.TH kbdcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+kbdcontrol - a utility for manipulating the syscons keyboard driver section.
+.SH SYNOPSIS
+.na
+.B kbdcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B kbdcontrol
+command is used to set various keyboard related options for the syscons
+console driver, such as keymap, keyboard repeat & delay rates, bell
+characteristics etc.
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-b\ " [ duration.pitch ]
+Set the bell duration and pitch values.
+.TP
+.BI "\-r\ " [ delay.repeat | slow | fast | normal ]
+Set keyboard
+.I delay
+and
+.I repeat
+rates, or use presets for
+.I slow,
+.I fast
+or
+.I normal.
+.TP
+.BI "\-l\ " mapfile
+Install keyboard map file from
+.I mapfile
+.TP
+.BI "\-d\ "
+Dump the current keyboard map onto stdout
+.TP
+.BI "\-f\ " #\ string
+Set function key number
+.I #
+to send
+.I string
+.
+.TP
+.BI "\-F\ "
+Set function keys back to the standard definitions.
+.TP
+.B \-v
+Turns on verbose output.
+.PP
+.SH FILES
+/usr/share/syscons/keymaps
+.SH "BUGS"
+Report when found.
+.SH "SEE ALSO"
+.BR vidcontrol (1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/SYSCONS
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c
new file mode 100644
index 0000000..cda976b
--- /dev/null
+++ b/usr.sbin/kbdcontrol/kbdcontrol.c
@@ -0,0 +1,566 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 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.
+ *
+ * $Id: kbdcontrol.c,v 1.1 1994/05/20 12:18:05 sos Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include "path.h"
+#include "lex.h"
+
+char ctrl_names[32][4] = {
+ "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
+ "bs ", "ht ", "nl ", "vt ", "ff ", "cr ", "so ", "si ",
+ "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
+ "can", "em ", "sub", "esc", "fs ", "gs ", "rs ", "ns "
+ };
+
+char fkey_table[60][MAXFK] = {
+/* 00-03 */ "\033[M", "\033[N", "\033[O", "\033[P",
+/* 04-07 */ "\033[Q", "\033[R", "\033[S", "\033[T",
+/* 08-0B */ "\033[U", "\033[V", "\033[W", "\033[X",
+/* 0C-0F */ "\033[W", "\033[X", "\033[Y", "\033[Z",
+/* 10-13 */ "\033[a", "\033[b", "\033[c", "\033[d",
+/* 14-17 */ "\033[e", "\033[f", "\033[g", "\033[h",
+/* 18-1B */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 1C-1F */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 20-23 */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 24-27 */ "\033[g", "\033[h", "\033[i", "\033[j",
+/* 28-2B */ "\033[k", "\033[l", "\033[m", "\033[n",
+/* 2C-2F */ "\033[o", "\033[p", "\033[q", "\033[r",
+/* 30-33 */ "\033[H", "\033[A", "\033[I", "-" ,
+/* 34-37 */ "\033[D", "\177" , "\033[C", "+" ,
+/* 38-3B */ "\033[F", "\033[B", "\033[G", "\033[L"
+ };
+
+const int delays[] = {250, 500, 750, 1000};
+const int repeats[] = { 34, 38, 42, 46, 50, 55, 59, 63,
+ 68, 76, 84, 92, 100, 110, 118, 126,
+ 136, 152, 168, 184, 200, 220, 236, 252,
+ 272, 304, 336, 368, 400, 440, 472, 504};
+const int ndelays = (sizeof(delays) / sizeof(int));
+const int nrepeats = (sizeof(repeats) / sizeof(int));
+int hex = 0;
+int number, verbose = 0;
+char letter;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+int
+get_entry()
+{
+ switch (yylex()) {
+ case TNOP:
+ return NOP | 0x100;
+ case TLSH:
+ return LSH | 0x100;
+ case TRSH:
+ return RSH | 0x100;
+ case TCLK:
+ return CLK | 0x100;
+ case TNLK:
+ return NLK | 0x100;
+ case TSLK:
+ return SLK | 0x100;
+ case TBTAB:
+ return BTAB | 0x100;
+ case TLALT:
+ return LALT | 0x100;
+ case TLCTR:
+ return LCTR | 0x100;
+ case TNEXT:
+ return NEXT | 0x100;
+ case TRCTR:
+ return RCTR | 0x100;
+ case TRALT:
+ return RALT | 0x100;
+ case TALK:
+ return ALK | 0x100;
+ case TASH:
+ return ASH | 0x100;
+ case TMETA:
+ return META | 0x100;
+ case TRBT:
+ return RBT | 0x100;
+ case TDBG:
+ return DBG | 0x100;
+ case TFUNC:
+ if (F(number) > L_FN)
+ return -1;
+ return F(number) | 0x100;
+ case TSCRN:
+ if (S(number) > L_SCR)
+ return -1;
+ return S(number) | 0x100;
+ case TLET:
+ return (unsigned char)letter;
+ case TNUM:
+ if (number < 0 || number > 255)
+ return -1;
+ return number;
+ default:
+ return -1;
+ }
+}
+
+
+int
+get_key_definition_line(FILE* fd, keymap_t *map)
+{
+ int i, def, scancode;
+
+ yyin = fd;
+
+ /* get scancode number */
+ if (yylex() != TNUM)
+ return -1;
+ if (number < 0 || number >= NUM_KEYS)
+ return -1;
+ scancode = number;
+
+ /* get key definitions */
+ map->key[scancode].spcl = 0;
+ for (i=0; i<NUM_STATES; i++) {
+ if ((def = get_entry()) == -1)
+ return -1;
+ if (def & 0x100)
+ map->key[scancode].spcl |= (0x80 >> i);
+ map->key[scancode].map[i] = def & 0xFF;
+ }
+ /* get lock state key def */
+ if (yylex() != TFLAG)
+ return -1;
+ map->key[scancode].flgs = number;
+ return scancode;
+}
+
+
+int
+print_entry(FILE *fp, int value)
+{
+ int val = value & 0xFF;
+
+ switch (value) {
+ case NOP | 0x100:
+ fprintf(fp, " nop ");
+ break;
+ case LSH | 0x100:
+ fprintf(fp, " lshift");
+ break;
+ case RSH | 0x100:
+ fprintf(fp, " rshift");
+ break;
+ case CLK | 0x100:
+ fprintf(fp, " clock ");
+ break;
+ case NLK | 0x100:
+ fprintf(fp, " nlock ");
+ break;
+ case SLK | 0x100:
+ fprintf(fp, " slock ");
+ break;
+ case BTAB | 0x100:
+ fprintf(fp, " btab ");
+ break;
+ case LALT | 0x100:
+ fprintf(fp, " lalt ");
+ break;
+ case LCTR | 0x100:
+ fprintf(fp, " lctrl ");
+ break;
+ case NEXT | 0x100:
+ fprintf(fp, " nscr ");
+ break;
+ case RCTR | 0x100:
+ fprintf(fp, " rctrl ");
+ break;
+ case RALT | 0x100:
+ fprintf(fp, " ralt ");
+ break;
+ case ALK | 0x100:
+ fprintf(fp, " alock ");
+ break;
+ case ASH | 0x100:
+ fprintf(fp, " ashift");
+ break;
+ case META | 0x100:
+ fprintf(fp, " meta ");
+ break;
+ case RBT | 0x100:
+ fprintf(fp, " boot ");
+ break;
+ case DBG | 0x100:
+ fprintf(fp, " debug ");
+ break;
+ default:
+ if (value & 0x100) {
+ if (val >= F_FN && val <= L_FN)
+ fprintf(fp, " fkey%02d", val - F_FN + 1);
+ else if (val >= F_SCR && val <= L_SCR)
+ fprintf(fp, " scr%02d ", val - F_SCR + 1);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ else {
+ if (val < ' ')
+ fprintf(fp, " %s ", ctrl_names[val]);
+ else if (val == 127)
+ fprintf(fp, " del ");
+ else if (isprint(val))
+ fprintf(fp, " '%c' ", val);
+ else if (hex)
+ fprintf(fp, " 0x%02x ", val);
+ else
+ fprintf(fp, " %3d ", val);
+ }
+ }
+}
+
+
+void
+print_key_definition_line(FILE *fp, int scancode, struct key_t *key)
+{
+ int i, value;
+
+ /* print scancode number */
+ if (hex)
+ fprintf(fp, " 0x%02x ", scancode);
+ else
+ fprintf(fp, " %03d ", scancode);
+
+ /* print key definitions */
+ for (i=0; i<NUM_STATES; i++) {
+ if (key->spcl & (0x80 >> i))
+ print_entry(fp, key->map[i] | 0x100);
+ else
+ print_entry(fp, key->map[i]);
+ }
+
+ /* print lock state key def */
+ switch (key->flgs) {
+ case 0:
+ fprintf(fp, " O\n");
+ break;
+ case 1:
+ fprintf(fp, " C\n");
+ break;
+ case 2:
+ fprintf(fp, " N\n");
+ break;
+ }
+}
+
+
+void
+load_keymap(char *opt)
+{
+ keymap_t map;
+ FILE *fd;
+ int scancode, i;
+ char *name;
+ char *prefix[] = {"", "", KEYMAP_PATH, NULL};
+ char *postfix[] = {"", ".kbd", ".kbd"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], opt, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("keymap file not found");
+ return;
+ }
+ memset(map, 0, sizeof(map));
+ while (1) {
+ if ((scancode = get_key_definition_line(fd, &map)) < 0)
+ break;
+ if (scancode > map.n_keys) map.n_keys = scancode;
+ }
+ if (ioctl(0, PIO_KEYMAP, &map) < 0) {
+ perror("setting keymap");
+ fclose(fd);
+ return;
+ }
+}
+
+
+void
+print_keymap()
+{
+ keymap_t map;
+ int i;
+
+ if (ioctl(0, GIO_KEYMAP, &map) < 0) {
+ perror("getting keymap");
+ exit(1);
+ }
+ printf(
+"# alt\n"
+"# scan cntrl alt alt cntrl lock\n"
+"# code base shift cntrl shift alt shift cntrl shift state\n"
+"# ------------------------------------------------------------------\n"
+ );
+ for (i=0; i<map.n_keys; i++)
+ print_key_definition_line(stdout, i, &map.key[i]);
+}
+
+
+void
+load_default_functionkeys()
+{
+ fkeyarg_t fkey;
+ int i;
+
+ for (i=0; i<NUM_FKEYS; i++) {
+ fkey.keynum = i;
+ strcpy(fkey.keydef, fkey_table[i]);
+ fkey.flen = strlen(fkey_table[i]);
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+ }
+}
+
+void
+set_functionkey(char *keynumstr, char *string)
+{
+ fkeyarg_t fkey;
+ int keynum;
+
+ if (!strcmp(keynumstr, "load") && !strcmp(string, "default")) {
+ load_default_functionkeys();
+ return;
+ }
+ fkey.keynum = atoi(keynumstr);
+ if (fkey.keynum < 1 || fkey.keynum > NUM_FKEYS) {
+ fprintf(stderr,
+ "function key number must be between 1 and %d\n",
+ NUM_FKEYS);
+ return;
+ }
+ if ((fkey.flen = strlen(string)) > MAXFK) {
+ fprintf(stderr, "function key string too long (%d > %d)\n",
+ fkey.flen, MAXFK);
+ return;
+ }
+ strcpy(fkey.keydef, string);
+ if (verbose)
+ fprintf(stderr, "setting function key %d to <%s>\n",
+ fkey.keynum, fkey.keydef);
+ fkey.keynum -= 1;
+ if (ioctl(0, SETFKEY, &fkey) < 0)
+ perror("setting function key");
+}
+
+
+void
+set_bell_values(char *opt)
+{
+ int duration, pitch;
+
+ if (!strcmp(opt, "normal"))
+ duration = 1, pitch = 15;
+ else {
+ int n;
+ char *v1;
+
+ duration = strtol(opt, &v1, 0);
+ if ((duration < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ pitch = strtol(opt, &v1, 0);
+ if ((pitch < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -b must be DURATION.PITCH\n");
+ return;
+ }
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting bell values to %d.%d\n",
+ duration, pitch);
+ fprintf(stderr, "[=%d;%dB", pitch, duration);
+}
+
+
+void
+set_keyrates(char *opt)
+{
+struct {
+ int rep:5;
+ int del:2;
+ int pad:1;
+ }rate;
+
+ if (!strcmp(opt, "slow"))
+ rate.del = 3, rate.rep = 31;
+ else if (!strcmp(opt, "normal"))
+ rate.del = 1, rate.rep = 15;
+ else if (!strcmp(opt, "fast"))
+ rate.del = rate.rep = 0;
+ else {
+ int n;
+ int delay, repeat;
+ char *v1;
+
+ delay = strtol(opt, &v1, 0);
+ if ((delay < 0) || (*v1 != '.'))
+ goto badopt;
+ opt = ++v1;
+ repeat = strtol(opt, &v1, 0);
+ if ((repeat < 0) || (*opt == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -r must be delay.repeat\n");
+ return;
+ }
+ for (n = 0; n < ndelays - 1; n++)
+ if (delay <= delays[n])
+ break;
+ rate.del = n;
+ for (n = 0; n < nrepeats - 1; n++)
+ if (repeat <= repeats[n])
+ break;
+ rate.rep = n;
+ }
+
+ if (verbose)
+ fprintf(stderr, "setting keyboard rate to %d.%d\n",
+ delays[rate.del], repeats[rate.rep]);
+ if (ioctl(0, KDSETRAD, rate) < 0)
+ perror("setting keyboard rate");
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: kbdcontrol -b duration.pitch (set bell duration & pitch)\n"
+" -d (dump keyboard map to stdout)\n"
+" -l filename (load keyboard map file)\n"
+" -f <N> string (set function key N to send <string>)\n"
+" -F (set function keys back to default)\n"
+" -r delay.repeat (set keyboard delay & repeat rate)\n"
+" -r slow (set keyboard delay & repeat to slow)\n"
+" -r normal (set keyboard delay & repeat to normal)\n"
+" -r fast (set keyboard delay & repeat to fast)\n"
+" -v (verbose)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+ /*
+ if (!is_syscons(0))
+ exit(1);
+ */
+ while((opt = getopt(argc, argv, "b:df:Fl:r:vx")) != -1)
+ switch(opt) {
+ case 'b':
+ set_bell_values(optarg);
+ break;
+ case 'd':
+ print_keymap();
+ break;
+ case 'l':
+ load_keymap(optarg);
+ break;
+ case 'f':
+ set_functionkey(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'F':
+ load_default_functionkeys();
+ break;
+ case 'r':
+ set_keyrates(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
+
diff --git a/usr.sbin/kbdcontrol/lex.h b/usr.sbin/kbdcontrol/lex.h
new file mode 100644
index 0000000..feff740
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.h
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 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.
+ *
+ * $Id: lex.h,v 1.1 1994/05/20 12:18:06 sos Exp $
+ */
+
+#define TNOP 256
+#define TLSH 257
+#define TRSH 258
+#define TCLK 259
+#define TNLK 260
+#define TSLK 261
+#define TLALT 262
+#define TLCTR 263
+#define TNEXT 264
+#define TRCTR 265
+#define TRALT 266
+#define TALK 267
+#define TASH 268
+#define TMETA 269
+#define TRBT 270
+#define TDBG 271
+#define TFUNC 272
+#define TSCRN 273
+#define TLET 274
+#define TNUM 275
+#define TFLAG 276
+#define TBTAB 277
+
+extern int number;
+extern char letter;
+extern FILE *yyin;
diff --git a/usr.sbin/kbdcontrol/lex.l b/usr.sbin/kbdcontrol/lex.l
new file mode 100644
index 0000000..0729af7
--- /dev/null
+++ b/usr.sbin/kbdcontrol/lex.l
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 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.
+ *
+ * $Id: lex.l,v 1.1 1994/05/20 12:18:08 sos Exp $
+ */
+
+%{
+
+#include "lex.h"
+
+%}
+
+D [0-9]
+X [0-9a-fA-F]
+A .
+L [OCN]
+
+%%
+
+nop { return TNOP; }
+lshift { return TLSH; }
+rshift { return TRSH; }
+clock { return TCLK; }
+nlock { return TNLK; }
+slock { return TSLK; }
+lalt|alt { return TLALT; }
+btab { return TBTAB; }
+lctrl|ctrl { return TLCTR; }
+nscr { return TNEXT; }
+rctrl { return TRCTR; }
+ralt { return TRALT; }
+alock { return TALK; }
+ashift { return TASH; }
+meta { return TMETA; }
+boot { return TRBT; }
+debug { return TDBG; }
+
+NUL|nul { number = 0; return TNUM; }
+SOH|soh { number = 1; return TNUM; }
+STX|stx { number = 2; return TNUM; }
+ETX|etx { number = 3; return TNUM; }
+EOT|eot { number = 4; return TNUM; }
+ENQ|enq { number = 5; return TNUM; }
+ACK|ack { number = 6; return TNUM; }
+BEL|bel { number = 7; return TNUM; }
+BS|bs { number = 8; return TNUM; }
+HT|ht { number = 9; return TNUM; }
+LF|lf|NL|nl { number = 10; return TNUM; }
+VT|vt { number = 11; return TNUM; }
+FF|ff|NP|np { number = 12; return TNUM; }
+CR|cr { number = 13; return TNUM; }
+SO|so { number = 14; return TNUM; }
+SI|si { number = 15; return TNUM; }
+DLE|dle { number = 16; return TNUM; }
+DC1|dc1 { number = 17; return TNUM; }
+DC2|dc2 { number = 18; return TNUM; }
+DC3|dc3 { number = 19; return TNUM; }
+DC4|dc4 { number = 20; return TNUM; }
+NAK|nak { number = 21; return TNUM; }
+SYN|syn { number = 22; return TNUM; }
+ETB|etb { number = 23; return TNUM; }
+CAN|can { number = 24; return TNUM; }
+EM|em { number = 25; return TNUM; }
+SUB|sub { number = 26; return TNUM; }
+ESC|esc { number = 27; return TNUM; }
+FS|fs { number = 28; return TNUM; }
+GS|gs { number = 29; return TNUM; }
+RS|rs { number = 30; return TNUM; }
+NS|ns { number = 31; return TNUM; }
+SP|sp { number = 32; return TNUM; }
+DEL|del { number = 127; return TNUM; }
+
+fkey{D}({D}*) {
+ sscanf(yytext+4, "%d", &number);
+ return TFUNC;
+ }
+scr{D}({D}*) {
+ sscanf(yytext+3, "%d", &number);
+ return TSCRN;
+ }
+'{A}' { letter = *(yytext+1); return TLET; }
+#({A}*) { /* ignore */ }
+0x{X}({X}*) { sscanf(yytext, "%x", &number); return TNUM; }
+{D}({D}*) { sscanf(yytext, "%d", &number); return TNUM; }
+{L} {
+ if (*yytext == 'O') number = 0;
+ if (*yytext == 'C') number = 1;
+ if (*yytext == 'N') number = 2;
+ return TFLAG;
+ }
+[ \t\n] { /* ignore */ }
diff --git a/usr.sbin/kbdcontrol/path.h b/usr.sbin/kbdcontrol/path.h
new file mode 100644
index 0000000..709acbc
--- /dev/null
+++ b/usr.sbin/kbdcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/kgmon/Makefile b/usr.sbin/kgmon/Makefile
new file mode 100644
index 0000000..20fcf68
--- /dev/null
+++ b/usr.sbin/kgmon/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= kgmon
+MAN8= 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 0000000..114fea8
--- /dev/null
+++ b/usr.sbin/kgmon/kgmon.8
@@ -0,0 +1,122 @@
+.\" 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.
+.\"
+.\" @(#)kgmon.8 8.1 (Berkeley) 6/6/93
+.\"
+.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 ``/kernel''.
+.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 /kernel
+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 0000000..cf75723
--- /dev/null
+++ b/usr.sbin/kgmon/kgmon.c
@@ -0,0 +1,520 @@
+/*
+ * 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[] = "@(#)kgmon.c 8.1 (Berkeley) 6/6/93";
+#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 = (char *)getbootfile();
+ 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, size, openmode;
+ 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;
+
+ 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], sz, oldstate;
+
+ 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], 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], size, profrate;
+ 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 0000000..c158a48
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= kvm_mkdb
+SRCS= kvm_mkdb.c nlist.c testdb.c
+MAN8= 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 0000000..6d72268
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/extern.h
@@ -0,0 +1,38 @@
+/*-
+ * 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.
+ *
+ * @(#)extern.h 8.1 (Berkeley) 6/6/93
+ */
+
+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 0000000..6b14e08
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/kvm_mkdb.8
@@ -0,0 +1,69 @@
+.\" 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.
+.\"
+.\" @(#)kvm_mkdb.8 8.1 (Berkeley) 6/9/93
+.\"
+.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 /kernel
+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_kernel.db -compact
+.It Pa /kernel
+.It Pa /var/db/kvm_kernel.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 0000000..2315352
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/kvm_mkdb.c
@@ -0,0 +1,111 @@
+/*-
+ * 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[] = "@(#)kvm_mkdb.c 8.1 (Berkeley) 6/6/93";
+#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));
+
+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] : (char *)getbootfile();
+ 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, NULL);
+ 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 0000000..f1d004c
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/nlist.c
@@ -0,0 +1,200 @@
+/*-
+ * 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[] = "@(#)nlist.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+
+#include <vm/vm.h>
+#include <vm/vm_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
+/*
+ * XXX
+ * The FreeBSD bootloader loads the kernel at the a_entry address, meaning
+ * that this is where the kernel starts. (not at KERNBASE)
+ *
+ * This may be introducing an i386 dependency.
+ */
+#if defined(__FreeBSD__)
+#define KERNTEXTOFF ebuf.a_entry
+#else
+#define KERNTEXTOFF KERNBASE
+#endif
+#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 0000000..fe4581e
--- /dev/null
+++ b/usr.sbin/kvm_mkdb/testdb.c
@@ -0,0 +1,113 @@
+/*-
+ * 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[] = "@(#)testdb.c 8.1 (Berkeley) 6/6/93";
+#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 = (char *)getbootfile();
+ 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 0000000..9b4d7d2
--- /dev/null
+++ b/usr.sbin/lpr/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= lpc lpd lpq lpr lprm lptest pac filters
+
+.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 0000000..65ecd4e
--- /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 0000000..1d34e9e
--- /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 0000000..9da2ae2
--- /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 0000000..8c950a9
--- /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 0000000..8800bc0
--- /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 0000000..137a342
--- /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 0000000..7087790
--- /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 0000000..a6f6bea
--- /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 0000000..1701c86
--- /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 0000000..bf31319
--- /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 0000000..49f7939
--- /dev/null
+++ b/usr.sbin/lpr/common_source/common.c
@@ -0,0 +1,352 @@
+/*
+ * 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 */
+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 };
+
+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:
+ s = rresvport(&lport);
+ 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;
+
+ if ((dirp = opendir(SD)) == NULL)
+ return(-1);
+ if (fstat(dirp->dd_fd, &stbuf) < 0)
+ goto errdone;
+
+ /*
+ * 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 */
+ if (stat(d->d_name, &stbuf) < 0)
+ continue; /* Doesn't exist */
+ 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 0000000..59d3cc9
--- /dev/null
+++ b/usr.sbin/lpr/common_source/displayq.c
@@ -0,0 +1,449 @@
+/*
+ * 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 */
+
+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;
+ 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
+ */
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spooling directory");
+ if ((nitems = getq(&queue)) < 0)
+ fatal("cannot examine spooling area\n");
+ if (stat(LO, &statb) >= 0) {
+ if (statb.st_mode & 0100) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s is down: ", printer);
+ fd = open(ST, 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 */
+ } else
+ putchar('\n');
+ }
+ if (statb.st_mode & 010) {
+ if (sendtorem)
+ printf("%s: ", host);
+ printf("Warning: %s queue is turned off\n", printer);
+ }
+ }
+
+ if (nitems) {
+ fp = fopen(LO, "r");
+ 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 || kill(i, 0) < 0)
+ warn();
+ else {
+ /* 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);
+ fd = open(ST, 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 */
+ } 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
+ */
+ if ((cfp = fopen(cf, "r")) == NULL)
+ return;
+
+ 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;
+ }
+ if (*file && !stat(file, &lbuf))
+ totsize += copies * lbuf.st_size;
+}
+
+/*
+ * 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 0000000..6dd1bf0
--- /dev/null
+++ b/usr.sbin/lpr/common_source/lp.h
@@ -0,0 +1,126 @@
+/*
+ * 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 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 0000000..837fd2f
--- /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 0000000..5c07cdb
--- /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 0000000..627d2ce
--- /dev/null
+++ b/usr.sbin/lpr/common_source/printcap.c
@@ -0,0 +1,458 @@
+/*
+ * 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 && (pfp = fopen(_PATH_PRINTCAP, "r")) == 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 {
+ tf = open(_PATH_PRINTCAP, 0);
+ }
+ } else
+ tf = open(cp, 0);
+ }
+ if (tf==0)
+ tf = open(_PATH_PRINTCAP, 0);
+#else
+ tf = open(_PATH_PRINTCAP, 0);
+#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/recvjob.c b/usr.sbin/lpr/common_source/recvjob.c
new file mode 100644
index 0000000..67a6183
--- /dev/null
+++ b/usr.sbin/lpr/common_source/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/common_source/rmjob.c b/usr.sbin/lpr/common_source/rmjob.c
new file mode 100644
index 0000000..74a94d8
--- /dev/null
+++ b/usr.sbin/lpr/common_source/rmjob.c
@@ -0,0 +1,339 @@
+/*
+ * 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 */
+
+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;
+ }
+
+ if (chdir(SD) < 0)
+ fatal("cannot chdir to spool directory");
+ if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
+ fatal("cannot access spool directory");
+
+ 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)) {
+ assasinated = kill(cur_daemon, SIGINT) == 0;
+ 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;
+
+ if ((fp = fopen(s, "r")) == NULL)
+ if (errno == EACCES)
+ fatal("can't access lock file");
+ else
+ return(0);
+ if (!getline(fp)) {
+ (void) fclose(fp);
+ return(0); /* no daemon present */
+ }
+ cur_daemon = atoi(line);
+ if (kill(cur_daemon, 0) < 0) {
+ (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;
+ if ((cfp = fopen(file, "r")) == NULL)
+ fatal("cannot open %s", file);
+ while (getline(cfp)) {
+ switch (line[0]) {
+ case 'U': /* unlink associated files */
+ if (from != host)
+ printf("%s: ", host);
+ printf(unlink(line+1) ? "cannot dequeue %s\n" :
+ "%s dequeued\n", line+1);
+ }
+ }
+ (void) fclose(cfp);
+ if (from != host)
+ printf("%s: ", host);
+ printf(unlink(file) ? "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.
+ */
+ if ((cfp = fopen(file, "r")) == NULL)
+ return(0);
+ 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 0000000..237769e
--- /dev/null
+++ b/usr.sbin/lpr/common_source/startdaemon.c
@@ -0,0 +1,108 @@
+/*
+ * 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"
+
+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
+ if (connect(s, (struct sockaddr *)&un, SUN_LEN(&un)) < 0) {
+ perr("connect");
+ (void) close(s);
+ return(0);
+ }
+ (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 0000000..c9d5c4f
--- /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 0000000..5335f31
--- /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 0000000..4aeeab7
--- /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
+MAN8= 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 0000000..7c2b6fe
--- /dev/null
+++ b/usr.sbin/lpr/lpc/cmds.c
@@ -0,0 +1,1107 @@
+/*
+ * 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"
+
+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;
+
+ 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) {
+ 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");
+ }
+ return;
+ } else {
+ printf("\tcannot stat lock file\n");
+ return;
+ }
+ }
+ /*
+ * Kill the current daemon to stop printing now.
+ */
+ if ((fp = fopen(line, "r")) == NULL) {
+ printf("\tcannot open lock file\n");
+ return;
+ }
+ if (!getline(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) {
+ (void) fclose(fp); /* unlocks as well */
+ printf("\tno daemon to abort\n");
+ return;
+ }
+ (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);
+}
+
+/*
+ * 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] = '/';
+
+ nitems = scandir(SD, &queue, doselect, sortq);
+ 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;
+{
+ if (unlink(name) < 0)
+ printf("\tcannot remove %s\n", name);
+ else
+ printf("\tremoved %s\n", name);
+}
+
+/*
+ * 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.
+ */
+ if (stat(line, &stbuf) >= 0) {
+ if (chmod(line, stbuf.st_mode & 0767) < 0)
+ printf("\tcannot enable queuing\n");
+ else
+ printf("\tqueuing enabled\n");
+ }
+}
+
+/*
+ * 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.
+ */
+ 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");
+ }
+ return;
+ } else
+ printf("\tcannot stat lock file\n");
+}
+
+/*
+ * 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);
+ 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");
+ }
+ 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");
+ return;
+ }
+ (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.
+ */
+ 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");
+}
+
+/*
+ * 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.
+ */
+ 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");
+}
+
+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);
+
+ if (chdir(SD) < 0) {
+ printf("\tcannot chdir to %s\n", SD);
+ return;
+ }
+ 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.
+ */
+ if (changed && stat(LO, &stbuf) >= 0)
+ (void) chmod(LO, (stbuf.st_mode & 0777) | 01);
+}
+
+/*
+ * Reposition the job by changing the modification time of
+ * the control file.
+ */
+static int
+touch(q)
+ struct queue *q;
+{
+ struct timeval tvp[2];
+
+ tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ return(utimes(q->q_name, tvp));
+}
+
+/*
+ * 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; ) {
+ if ((fp = fopen((*qq)->q_name, "r")) == 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 0000000..7619791
--- /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 0000000..1b807b1
--- /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 0000000..a786adc
--- /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 0000000..01cfc12
--- /dev/null
+++ b/usr.sbin/lpr/lpc/lpc.c
@@ -0,0 +1,277 @@
+/*
+ * 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
+ */
+
+int fromatty;
+
+char cmdline[200];
+int margc;
+char *margv[20];
+int top;
+
+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;
+
+ 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, sizeof(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;
+
+ 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;
+
+ 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 0000000..5e71203
--- /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 0000000..ee996d4
--- /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
+MAN8= lpd.8
+SRCS= lpd.c printjob.c recvjob.c displayq.c rmjob.c startdaemon.c \
+ lpdchar.c common.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 0000000..64dec12
--- /dev/null
+++ b/usr.sbin/lpr/lpd/extern.h
@@ -0,0 +1,39 @@
+/*
+ * 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>
+
+void printjob __P((void));
+void recvjob __P((void));
diff --git a/usr.sbin/lpr/lpd/lpd.8 b/usr.sbin/lpr/lpd/lpd.8
new file mode 100644
index 0000000..1e4677f
--- /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 0000000..aaf72b7
--- /dev/null
+++ b/usr.sbin/lpr/lpd/lpd.c
@@ -0,0 +1,507 @@
+/*
+ * 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 *));
+
+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;
+
+ 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 0000000..4a4f5da
--- /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/printjob.c b/usr.sbin/lpr/lpd/printjob.c
new file mode 100644
index 0000000..87c9352
--- /dev/null
+++ b/usr.sbin/lpr/lpd/printjob.c
@@ -0,0 +1,1377 @@
+/*
+ * 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 <sgtty.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 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;
+
+ 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)
+ 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;
+
+ 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, EXTA,
+ 38400, EXTB,
+ 0, 0
+};
+
+/*
+ * setup tty lines.
+ */
+static void
+setty()
+{
+ struct sgttyb ttybuf;
+ register struct bauds *bp;
+
+ if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
+ exit(1);
+ }
+ if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %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);
+ }
+ ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
+ }
+ ttybuf.sg_flags &= ~FC;
+ ttybuf.sg_flags |= FS;
+ if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
+ exit(1);
+ }
+ if (XC) {
+ if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
+ exit(1);
+ }
+ }
+ if (XS) {
+ if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
+ exit(1);
+ }
+ }
+}
+
+#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 0000000..67a6183
--- /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/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile
new file mode 100644
index 0000000..0240b57
--- /dev/null
+++ b/usr.sbin/lpr/lpq/Makefile
@@ -0,0 +1,13 @@
+# @(#)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
+MAN1= lpq.1
+.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 0000000..50e1474
--- /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 0000000..b091e8e
--- /dev/null
+++ b/usr.sbin/lpr/lpq/lpq.c
@@ -0,0 +1,126 @@
+/*
+ * 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 */
+
+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 */
+
+ 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 0000000..eed68fd
--- /dev/null
+++ b/usr.sbin/lpr/lpr/Makefile
@@ -0,0 +1,13 @@
+# @(#)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
+MAN1= lpr.1
+.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 0000000..382d508
--- /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 0000000..8e9c45f
--- /dev/null
+++ b/usr.sbin/lpr/lpr/lpr.c
@@ -0,0 +1,744 @@
+/*
+ * 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 *));
+
+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;
+
+ 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);
+ (void) fchown(tfd, DU, -1); /* owned by daemon for protection */
+ 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);
+ if ((i = open(arg, O_RDONLY)) < 0) {
+ 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);
+ }
+
+ if (nact) {
+ (void) close(tfd);
+ tfname[inchar]--;
+ /*
+ * Touch the control file to fix position in the queue.
+ */
+ 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);
+ 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];
+
+ if (*file != '/') {
+ if (getwd(buf) == NULL)
+ 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;
+ }
+ return(symlink(file, dfname) ? 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 */
+
+ 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);
+ }
+ 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;
+ 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;
+
+ if (access(file, 4) < 0) {
+ printf("%s: cannot access %s\n", name, file);
+ return(-1);
+ }
+ if (stat(file, &statb) < 0) {
+ printf("%s: cannot stat %s\n", name, file);
+ return(-1);
+ }
+ if ((statb.st_mode & S_IFMT) == S_IFDIR) {
+ printf("%s: %s is a directory\n", name, file);
+ return(-1);
+ }
+ if (statb.st_size == 0) {
+ printf("%s: %s is an empty file\n", name, file);
+ return(-1);
+ }
+ if ((fd = open(file, O_RDONLY)) < 0) {
+ printf("%s: cannot open %s\n", name, file);
+ return(-1);
+ }
+ if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
+ !N_BADMAG(execb)) {
+ printf("%s: %s is an executable program", name, file);
+ goto error1;
+ }
+ (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);
+
+error1:
+ printf(" and is unprintable\n");
+ (void) close(fd);
+ 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);
+ 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);
+ }
+ 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/lpr/printcap.5 b/usr.sbin/lpr/lpr/printcap.5
new file mode 100644
index 0000000..22d3100
--- /dev/null
+++ b/usr.sbin/lpr/lpr/printcap.5
@@ -0,0 +1,288 @@
+.\" 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.
+.\"
+.\" @(#)printcap.5 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt PRINTCAP 5
+.Os BSD 4.2
+.Sh NAME
+.Nm printcap
+.Nd printer capability data base
+.Sh SYNOPSIS
+.Nm printcap
+.Sh DESCRIPTION
+The
+.Nm Printcap
+function
+is a simplified version of the
+.Xr termcap 5
+data base
+used to describe line printers. The spooling system accesses the
+.Nm printcap
+file every time it is used, allowing dynamic
+addition and deletion of printers. Each entry in the data base
+is used to describe one printer. This data base may not be
+substituted for, as is possible for
+.Xr termcap ,
+because it may allow accounting to be bypassed.
+.Pp
+The default printer is normally
+.Em lp ,
+though the environment variable
+.Ev PRINTER
+may be used to override this. Each spooling utility supports an option,
+.Fl P Ar printer ,
+to allow explicit naming of a destination printer.
+.Pp
+Refer to the
+.%T "4.3 BSD Line Printer Spooler Manual"
+for a complete discussion on how to setup the database for a given printer.
+.Sh CAPABILITIES
+Refer to
+.Xr termcap 5
+for a description of the file layout.
+.Bl -column Namexxx Typexx "/var/spool/lpdxxxxx"
+.Sy Name Type Description
+.It "af str" Ta Dv NULL Ta No "name of accounting file"
+.It "br num none if lp is a tty, set the baud rate"
+.Pf ( Xr ioctl 2
+call)
+.It "cf str" Ta Dv NULL Ta No "cifplot data filter"
+.It "df str" Ta Dv NULL Ta No "tex data filter"
+.Pf ( Tn DVI
+format)
+.It "fc num 0 if lp is a tty, clear flag bits"
+.Pq Pa sgtty.h
+.It "ff str" Ta So Li \ef Sc Ta No "string to send for a form feed"
+.It "fo bool false print a form feed when device is opened"
+.It "fs num 0 like `fc' but set bits"
+.It "gf str" Ta Dv NULL Ta No "graph data filter"
+.Pf ( Xr plot 3
+format
+.It "hl bool false print the burst header page last"
+.It "ic bool false driver supports (non standard) ioctl to indent printout"
+.It "if str" Ta Dv NULL Ta No "name of text filter which does accounting"
+.It "lf str" Ta Pa /dev/console Ta No "error logging file name"
+.It "lo str" Ta Pa lock Ta No "name of lock file"
+.It "lp str" Ta Pa /dev/lp Ta No "device name to open for output"
+.It "mx num 1000 maximum file size (in"
+.Dv BUFSIZ
+blocks), zero = unlimited
+.It "nd str" Ta Dv NULL Ta No "next directory for list of queues (unimplemented)"
+.It "nf str" Ta Dv NULL Ta No "ditroff data filter (device independent troff)"
+.It "of str" Ta Dv NULL Ta No "name of output filtering program"
+.It "pc num 200 price per foot or page in hundredths of cents"
+.It "pl num 66 page length (in lines)"
+.It "pw num 132 page width (in characters)"
+.It "px num 0 page width in pixels (horizontal)"
+.It "py num 0 page length in pixels (vertical)"
+.It "rf str" Ta Dv NULL Ta No "filter for printing"
+.Tn FORTRAN
+style text files
+.It "rg str" Ta Dv NULL Ta No "restricted group. Only members of group allowed access"
+.It "rm str" Ta Dv NULL Ta No "machine name for remote printer"
+.It "rp str ``lp'' remote printer name argument"
+.It "rs bool false restrict remote users to those with local accounts"
+.It "rw bool false open the printer device for reading and writing"
+.It "sb bool false short banner (one line only)"
+.It "sc bool false suppress multiple copies"
+.It "sd str" Ta Pa /var/spool/lpd Ta No "spool directory"
+.It "sf bool false suppress form feeds"
+.It "sh bool false suppress printing of burst page header"
+.It "st str" Ta Pa status Ta No "status file name"
+.It "tf str" Ta Dv NULL Ta No "troff data filter (cat phototypesetter)"
+.It "tr str" Ta Dv NULL Ta No "trailer string to print when queue empties"
+.It "vf str" Ta Dv NULL Ta No "raster image filter"
+.It "xc num 0 if lp is a tty, clear local mode bits"
+.Pq Xr tty 4
+.It "xs num 0 like `xc' but set bits"
+.El
+.Pp
+If the local line printer driver supports indentation, the daemon
+must understand how to invoke it.
+.Sh FILTERS
+The
+.Xr lpd 8
+daemon creates a pipeline of
+.Em filters
+to process files for various printer types.
+The filters selected depend on the flags passed to
+.Xr lpr 1 .
+The pipeline set up is:
+.Bd -literal -offset indent
+p pr | if regular text + pr(1)
+none if regular text
+c cf cifplot
+d df DVI (tex)
+g gf plot(3)
+n nf ditroff
+f rf Fortran
+t tf troff
+v vf raster image
+.Ed
+.Pp
+The
+.Sy if
+filter is invoked with arguments:
+.Bd -filled -offset indent
+.Cm if
+.Op Fl c
+.Fl w Ns Ar width
+.Fl l Ns Ar length
+.Fl i Ns Ar indent
+.Fl n Ar login
+.Fl h Ar host acct-file
+.Ed
+.Pp
+The
+.Fl c
+flag is passed only if the
+.Fl l
+flag (pass control characters literally)
+is specified to
+.Xr lpr .
+The
+.Ar Width
+function
+and
+.Ar length
+specify the page width and length
+(from
+.Cm pw
+and
+.Cm pl
+respectively) in characters.
+The
+.Fl n
+and
+.Fl h
+parameters specify the login name and host name of the owner
+of the job respectively.
+The
+.Ar Acct-file
+function
+is passed from the
+.Cm af
+.Nm printcap
+entry.
+.Pp
+If no
+.Cm if
+is specified,
+.Cm of
+is used instead,
+with the distinction that
+.Cm of
+is opened only once,
+while
+.Cm if
+is opened for every individual job.
+Thus,
+.Cm if
+is better suited to performing accounting.
+The
+.Cm of
+is only given the
+.Ar width
+and
+.Ar length
+flags.
+.Pp
+All other filters are called as:
+.Bd -filled -offset indent
+.Nm filter
+.Fl x Ns Ar width
+.Fl y Ns Ar length
+.Fl n Ar login
+.Fl h Ar host acct-file
+.Ed
+.Pp
+where
+.Ar width
+and
+.Ar length
+are represented in pixels,
+specified by the
+.Cm px
+and
+.Cm py
+entries respectively.
+.Pp
+All filters take
+.Em stdin
+as the file,
+.Em stdout
+as the printer,
+may log either to
+.Em stderr
+or using
+.Xr syslog 3 ,
+and must not ignore
+.Dv SIGINT .
+.Sh LOGGING
+Error messages generated by the line printer programs themselves
+(that is, the
+.Xr lp Ns *
+programs)
+are logged by
+.Xr syslog 3
+using the
+.Dv LPR
+facility.
+Messages printed on
+.Em stderr
+of one of the filters
+are sent to the corresponding
+.Cm lf
+file.
+The filters may, of course, use
+.Xr syslog
+themselves.
+.Pp
+Error messages sent to the console have a carriage return and a line
+feed appended to them, rather than just a line feed.
+.Sh SEE ALSO
+.Xr termcap 5 ,
+.Xr lpc 8 ,
+.Xr lpd 8 ,
+.Xr pac 8 ,
+.Xr lpr 1 ,
+.Xr lpq 1 ,
+.Xr lprm 1
+.Rs
+.%T "4.3 BSD Line Printer Spooler Manual"
+.Re
+.Sh HISTORY
+The
+.Nm
+file format appeared in
+.Bx 4.2 ..
diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile
new file mode 100644
index 0000000..77c57e5
--- /dev/null
+++ b/usr.sbin/lpr/lprm/Makefile
@@ -0,0 +1,13 @@
+# @(#)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
+MAN1= lprm.1
+.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 0000000..22309d1
--- /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
+``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 0000000..20c4ee7
--- /dev/null
+++ b/usr.sbin/lpr/lprm/lprm.c
@@ -0,0 +1,144 @@
+/*
+ * 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 */
+
+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;
+
+ 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 0000000..8492b69
--- /dev/null
+++ b/usr.sbin/lpr/lptest/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= lptest
+MAN1= lptest.1
+
+.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 0000000..95b28f3
--- /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 0000000..5ce80b5
--- /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 0000000..1f49dea
--- /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
+MAN8= 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 0000000..6e7ffc0
--- /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 0000000..af0c8cc
--- /dev/null
+++ b/usr.sbin/lpr/pac/pac.c
@@ -0,0 +1,444 @@
+/*
+ * 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 */
+
+/*
+ * 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;
+
+ 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/lpr/runqueue/extern.h b/usr.sbin/lpr/runqueue/extern.h
new file mode 100644
index 0000000..64dec12
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/extern.h
@@ -0,0 +1,39 @@
+/*
+ * 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>
+
+void printjob __P((void));
+void recvjob __P((void));
diff --git a/usr.sbin/lpr/runqueue/lpdchar.c b/usr.sbin/lpr/runqueue/lpdchar.c
new file mode 100644
index 0000000..4a4f5da
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/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/runqueue/printjob.c b/usr.sbin/lpr/runqueue/printjob.c
new file mode 100644
index 0000000..87c9352
--- /dev/null
+++ b/usr.sbin/lpr/runqueue/printjob.c
@@ -0,0 +1,1377 @@
+/*
+ * 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 <sgtty.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 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;
+
+ 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)
+ 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;
+
+ 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, EXTA,
+ 38400, EXTB,
+ 0, 0
+};
+
+/*
+ * setup tty lines.
+ */
+static void
+setty()
+{
+ struct sgttyb ttybuf;
+ register struct bauds *bp;
+
+ if (ioctl(pfd, TIOCEXCL, (char *)0) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCEXCL): %m", printer);
+ exit(1);
+ }
+ if (ioctl(pfd, TIOCGETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCGETP): %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);
+ }
+ ttybuf.sg_ispeed = ttybuf.sg_ospeed = bp->speed;
+ }
+ ttybuf.sg_flags &= ~FC;
+ ttybuf.sg_flags |= FS;
+ if (ioctl(pfd, TIOCSETP, (char *)&ttybuf) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCSETP): %m", printer);
+ exit(1);
+ }
+ if (XC) {
+ if (ioctl(pfd, TIOCLBIC, &XC) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIC): %m", printer);
+ exit(1);
+ }
+ }
+ if (XS) {
+ if (ioctl(pfd, TIOCLBIS, &XS) < 0) {
+ syslog(LOG_ERR, "%s: ioctl(TIOCLBIS): %m", printer);
+ exit(1);
+ }
+ }
+}
+
+#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/lptcontrol/Makefile b/usr.sbin/lptcontrol/Makefile
new file mode 100644
index 0000000..110066d
--- /dev/null
+++ b/usr.sbin/lptcontrol/Makefile
@@ -0,0 +1,5 @@
+PROG= lptcontrol
+CFLAGS+= -Wall
+MAN8= lptcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/lptcontrol/lptcontrol.8 b/usr.sbin/lptcontrol/lptcontrol.8
new file mode 100644
index 0000000..4a02390
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.8
@@ -0,0 +1,73 @@
+.\"
+.\" lptcontrol - a utility for manipulating the lpt driver
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\"
+.\" $Id: lptcontrol.1,v 1.3 1994/05/22 12:31:54 csgr Exp $
+.Dd September 3, 1994
+.Dt LPTCONTROL 8
+.Os FreeBSD 2
+.Sh NAME
+.Nm \&lptcontrol
+.Nd a utility for manipulating the lpt printer driver.
+.Sh SYNOPSIS
+.Nm \&lptcontrol
+.Cm -i
+|
+.Cm -p
+.Op Fl u Ar unit no
+.Sh DESCRIPTION
+The
+.Nm lptcontrol
+command is used to set either the interrupt-driven or polling mode
+of individual
+.Xr lpt 4
+devices. When a printer is switched between
+interrupt-driven and polled mode, this change will only take effect
+the next time the device is opened.
+.Sh OPTIONS
+.TP
+The following command line options are supported:
+.Bl -tag -width indent
+.It Fl i
+Turns on interrupt-driven mode.
+.It Fl p
+Turns on polled mode.
+.It Fl u Ar n
+Sets the mode of the printer device specified by
+.Em n .
+The default value for
+.Em n
+is
+.Em 0 (ie. /dev/lpt0)
+.El
+.Pp
+One of
+.Fl i
+or
+.Fl p
+must be specified.
+.Pp
+.Sh FILES
+.Bl -tag -width indent -compact
+.It Pa /dev/lpt? - printer devices
+.It Pa /dev/lpctl? - printer control devices
+.El
+.Sh BUGS
+Sure to be some.
+.Sh "SEE ALSO"
+.Xr lpt 4
+.Xr /sys/i386/conf/GENERICAH
+.Sh AUTHOR
+Geoffrey M. Rehmet
+.Sh HISTORY
+.Nm lptcontrol
+first appeared in FreeBSD 1.1.5
diff --git a/usr.sbin/lptcontrol/lptcontrol.c b/usr.sbin/lptcontrol/lptcontrol.c
new file mode 100644
index 0000000..cbe0410
--- /dev/null
+++ b/usr.sbin/lptcontrol/lptcontrol.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1994 Geoffrey M. Rehmet
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Geoffrey M. Rehmet
+ * 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.
+ *
+ * $Id: lptcontrol.c,v 1.1.1.1 1994/09/03 13:10:09 csgr Exp $
+ */
+
+#include <ctype.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <machine/lpt.h>
+#include <sys/errno.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+
+#define PATH_LPCTL _PATH_DEV "lpctl"
+#define DEFAULT_UNIT "0"
+#define IRQ_INVALID -1
+#define DO_POLL 0
+#define USE_IRQ 1
+
+static void usage(const char * progname)
+{
+ fprintf(stderr, "usage: %s -i | -p [-u <unit no.>]\n", progname);
+ fprintf(stderr, "\tUnit no. is a value in the range 0 to 3\n");
+ fprintf(stderr, "\tThe default unit no is 0 (ie. /dev/lpt0)\n");
+ exit(1);
+}
+
+static void set_interrupt_status(int irq_status, const char * file)
+{
+ int fd;
+
+ if((fd = open(file, O_WRONLY, 0660)) < 0) {
+ perror("open");
+ exit(1);
+ }
+ if(ioctl(fd, LPT_IRQ, &irq_status) < 0) {
+ perror("ioctl");
+ exit(1);
+ }
+ close(fd);
+}
+
+static char * dev_file(char unit_no)
+{
+ static char devname[_POSIX_PATH_MAX+1];
+ int len;
+
+ strncpy(devname, PATH_LPCTL, _POSIX_PATH_MAX);
+ devname[len = strlen(devname)] = unit_no;
+ devname[++len] = '\0';
+
+ return(devname);
+}
+
+int main (int argc, char * argv[])
+{
+ int opt;
+ int irq_status = IRQ_INVALID;
+ char * unit = DEFAULT_UNIT;
+
+ while((opt = getopt(argc, argv, "ipu:")) != -1)
+ switch(opt) {
+ case 'i': irq_status = USE_IRQ; break;
+ case 'p': irq_status = DO_POLL; break;
+ case 'u': unit = optarg;
+ if(!isdigit(*unit))
+ usage(argv[0]);
+ break;
+ default : usage(argv[0]);
+ }
+ if(irq_status == IRQ_INVALID)
+ usage(argv[0]);
+
+ set_interrupt_status(irq_status, dev_file(*unit));
+
+ exit(0);
+}
+
+
diff --git a/usr.sbin/manctl/Makefile b/usr.sbin/manctl/Makefile
new file mode 100644
index 0000000..f56c66d
--- /dev/null
+++ b/usr.sbin/manctl/Makefile
@@ -0,0 +1,11 @@
+# Makefile
+# $Id: Makefile,v 1.3 1994/05/26 07:52:23 csgr Exp $
+
+all:
+ @echo -n
+
+install: all
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 ${.CURDIR}/manctl.sh \
+ ${DESTDIR}/usr/sbin/manctl
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/manctl/manctl.sh b/usr.sbin/manctl/manctl.sh
new file mode 100644
index 0000000..e00b190
--- /dev/null
+++ b/usr.sbin/manctl/manctl.sh
@@ -0,0 +1,376 @@
+#!/bin/sh
+#
+# Copyright (c) 1994 Geoffrey M. Rehmet, Rhodes University
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by Geoffrey M. Rehmet
+# 4. Neither the name of Geoffrey M. Rehmet nor that of Rhodes University
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL GEOFFREY M. REHMET OR RHODES UNIVERSITY BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (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: manctl,v 1.5 1994/04/18 15:39:29 g89r4222 Exp $
+#
+# manctl:
+# a utility for manipulating manual pages
+# functions:
+# compress uncompressed man pages (elliminating .so's)
+# this is now two-pass. If possible, .so's
+# are replaced with hard links
+# uncompress compressed man pages
+# purge old formatted man pages (not implemented yet)
+# Things to watch out for:
+# Hard links - careful with g(un)zipping!
+# .so's - throw everything through soelim before gzip!
+# symlinks - ignore these - eg: expn is its own man page:
+# don't want to compress this!
+#
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+
+#
+# purge cat? directories
+#
+do_purge()
+{
+ echo "purge $@" 2>&1
+ echo "not implemented yet\n" 2>&1
+}
+
+
+#
+# Uncompress one page
+#
+uncompress_page()
+{
+ local pname
+ local fname
+ local sect
+ local ext
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ # less than 3 fields - don't know what to do with this
+ if [ $# -lt 3 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 2 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+ ext=$2
+
+ IFS=" "
+ case "$ext" in
+ gz|Z) {
+ IFS=" " ; set `file $pname`
+ if [ $2 != "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $fname.$ext # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo gunzipping page $pname 1>&2
+ gunzip -c $pname > /tmp/manager.$$
+ chmod u+w $pname
+ cp /tmp/manager.$$ $pname
+ chmod 444 $pname
+ mv $pname $fname.$sect
+ rm /tmp/manager.$$
+ else
+ # skip symlinks - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+
+#
+# Uncompress manpages in paths
+#
+do_uncompress()
+{
+ local i
+ local dir
+ local workdir
+
+ workdir=`pwd`
+ while [ $# != 0 ] ; do
+ if [ -d $1 ] ; then
+ dir=$1
+ cd $dir
+ for i in * ; do
+ case $i in
+ *cat?) ;; # ignore cat directories
+ *) {
+ if [ -d $i ] ; then
+ do_uncompress $i
+ else
+ if [ -e $i ] ; then
+ uncompress_page $i
+ fi
+ fi } ;;
+ esac
+ done
+ cd $workdir
+ else
+ echo "directory $1 not found" 1>&2
+ fi
+ shift
+ done
+}
+
+#
+# Remove .so's from one file
+#
+so_purge_page()
+{
+ local so_entries
+ local lines
+ local fname
+
+ so_entries=`grep "^\.so" $1 | wc -l`
+ if [ $so_entries -eq 0 ] ; then ; return 0 ; fi
+
+ # we have a page with a .so in it
+ echo $1 contains a .so entry 2>&1
+
+ # now check how many lines in the file
+ lines=`wc -l < $1`
+
+ # if the file is only one line long, we can replace it
+ # with a hard link!
+ if [ $lines -eq 1 ] ; then
+ fname=$1;
+ echo replacing $fname with a hard link
+ set `cat $fname`;
+ rm -f $fname
+ ln ../$2 $fname
+ else
+ echo inlining page $fname 1>&2
+ cat $fname | \
+ (cd .. ; soelim ) > /tmp/manager.$$
+ chmod u+w $fname
+ cp /tmp/manager.$$ $fname
+ chmod 444 $fname
+ fi
+}
+
+#
+# Remove .so entries from man pages
+# If a page consists of just one line with a .so,
+# replace it with a hard link
+#
+remove_so()
+{
+ local pname
+ local fname
+ local sect
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ if [ $# -lt 2 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 1 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+
+ IFS=" "
+ case "$sect" in
+ gz) { echo file $pname already gzipped 1>&2 ; } ;;
+ Z) { echo file $pname already compressed 1>&2 ; } ;;
+ [12345678ln]*){
+ IFS=" " ; set `file $pname`
+ if [ $2 = "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $pname.gz # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo "removing .so's in page $pname" 1>&2
+ so_purge_page $pname
+ else
+ # skip symlink - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+
+#
+# compress one page
+# We need to watch out for hard links here.
+#
+compress_page()
+{
+ local pname
+ local fname
+ local sect
+
+ # break up file name
+ pname=$1
+ IFS='.' ; set $pname
+ if [ $# -lt 2 ] ; then
+ IFS=" " ; echo ignoring $pname 1>&2 ; return 0 ;
+ fi
+ # construct name and section
+ fname=$1 ; shift
+ while [ $# -gt 1 ] ; do
+ fname=$fname.$1
+ shift
+ done
+ sect=$1
+
+ IFS=" "
+ case "$sect" in
+ gz) { echo file $pname already gzipped 1>&2 ; } ;;
+ Z) { echo file $pname already compressed 1>&2 ; } ;;
+ [12345678ln]*){
+ IFS=" " ; set `file $pname`
+ if [ $2 = "gzip" ] ; then
+ echo moving hard link $pname 1>&2
+ mv $pname $pname.gz # link
+ else
+ if [ $2 != "symbolic" ] ; then
+ echo gzipping page $pname 1>&2
+ cat $pname | \
+ (cd .. ; soelim )| gzip -c -- > /tmp/manager.$$
+ chmod u+w $pname
+ cp /tmp/manager.$$ $pname
+ chmod 444 $pname
+ mv $pname $pname.gz
+ rm /tmp/manager.$$
+ else
+ # skip symlink - this can be
+ # a program like expn, which is
+ # its own man page !
+ echo skipping symlink $pname 1>&2
+ fi
+ fi };;
+ *) {
+ IFS=" "
+ echo skipping file $pname 1>&2
+ } ;;
+ esac
+ # reset IFS - this is important!
+ IFS=" "
+}
+
+#
+# Compress man pages in paths
+#
+do_compress_so()
+{
+ local i
+ local dir
+ local workdir
+ local what
+
+ what=$1
+ shift
+ workdir=`pwd`
+ while [ $# != 0 ] ; do
+ if [ -d $1 ] ; then
+ dir=$1
+ cd $dir
+ for i in * ; do
+ case $i in
+ *cat?) ;; # ignore cat directories
+ *) {
+ if [ -d $i ] ; then
+ do_compress_so $what $i
+ else
+ if [ -e $i ] ; then
+ $what $i
+ fi
+ fi } ;;
+ esac
+ done
+ cd $workdir
+ else
+ echo "directory $1 not found" 1>&2
+ fi
+ shift
+ done
+}
+
+#
+# Display a usage message
+#
+ctl_usage()
+{
+ echo "usage : $1 -compress <path> ... " 1>&2
+ echo " $1 -uncompress <path> ... " 1>&2
+ echo " $1 -purge <days> <path> ... " 1>&2
+ echo " $1 -purge expire <path> ... " 1>&2
+ exit 1
+}
+
+#
+# remove .so's and do compress
+#
+do_compress()
+{
+ # First remove all so's from the pages to be compressed
+ do_compress_so remove_so "$@"
+ # now do ahead and compress the pages
+ do_compress_so compress_page "$@"
+}
+
+#
+# dispatch options
+#
+if [ $# = 0 ] ; then ; ctl_usage $0 ; fi ;
+
+case "$1" in
+ -compress) shift ; do_compress "$@" ;;
+ -uncompress) shift ; do_uncompress "$@" ;;
+ -purge) shift ; do_purge "$@" ;;
+ *) ctl_usage $0 ;;
+esac
diff --git a/usr.sbin/mount_portalfs/Makefile b/usr.sbin/mount_portalfs/Makefile
new file mode 100644
index 0000000..4f32eda
--- /dev/null
+++ b/usr.sbin/mount_portalfs/Makefile
@@ -0,0 +1,15 @@
+# @(#)Makefile 8.3 (Berkeley) 3/27/94
+
+PROG= mount_portal
+SRCS= mount_portal.c activate.c conf.c getmntopts.c pt_conf.c \
+ pt_exec.c pt_file.c pt_tcp.c
+MAN8= mount_portal.8
+
+MOUNT= ${.CURDIR}/../mount
+CFLAGS+= -I/sys -I${MOUNT}
+.PATH: ${MOUNT}
+
+DPADD= $(LIBCOMPAT)
+LDADD= -lcompat
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mount_portalfs/activate.c b/usr.sbin/mount_portalfs/activate.c
new file mode 100644
index 0000000..3361798
--- /dev/null
+++ b/usr.sbin/mount_portalfs/activate.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)activate.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: activate.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/uio.h>
+
+#include "portald.h"
+
+/*
+ * Scan the providers list and call the
+ * appropriate function.
+ */
+static int activate_argv(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ provider *pr;
+
+ for (pr = providers; pr->pr_match; pr++)
+ if (strcmp(v[0], pr->pr_match) == 0)
+ return ((*pr->pr_func)(pcr, key, v, so, fdp));
+
+ return (ENOENT);
+}
+
+static int get_request(so, pcr, key, klen)
+int so;
+struct portal_cred *pcr;
+char *key;
+int klen;
+{
+ struct iovec iov[2];
+ struct msghdr msg;
+ int n;
+
+ iov[0].iov_base = (caddr_t) pcr;
+ iov[0].iov_len = sizeof(*pcr);
+ iov[1].iov_base = key;
+ iov[1].iov_len = klen;
+
+ bzero((char *) &msg, sizeof(msg));
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 2;
+
+ n = recvmsg(so, &msg, 0);
+ if (n < 0)
+ return (errno);
+
+ if (n <= sizeof(*pcr))
+ return (EINVAL);
+
+ n -= sizeof(*pcr);
+ key[n] = '\0';
+
+ return (0);
+}
+
+static void send_reply(so, fd, error)
+int so;
+int fd;
+int error;
+{
+ int n;
+ struct iovec iov;
+ struct msghdr msg;
+ struct {
+ struct cmsghdr cmsg;
+ int fd;
+ } ctl;
+
+ /*
+ * Line up error code. Don't worry about byte ordering
+ * because we must be sending to the local machine.
+ */
+ iov.iov_base = (caddr_t) &error;
+ iov.iov_len = sizeof(error);
+
+ /*
+ * Build a msghdr
+ */
+ bzero((char *) &msg, sizeof(msg));
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ /*
+ * If there is a file descriptor to send then
+ * construct a suitable rights control message.
+ */
+ if (fd >= 0) {
+ ctl.fd = fd;
+ ctl.cmsg.cmsg_len = sizeof(ctl);
+ ctl.cmsg.cmsg_level = SOL_SOCKET;
+ ctl.cmsg.cmsg_type = SCM_RIGHTS;
+ msg.msg_control = (caddr_t) &ctl;
+ msg.msg_controllen = ctl.cmsg.cmsg_len;
+ }
+
+ /*
+ * Send to kernel...
+ */
+ if ((n = sendmsg(so, &msg, MSG_EOR)) < 0)
+ syslog(LOG_ERR, "send: %s", strerror(errno));
+#ifdef DEBUG
+ fprintf(stderr, "sent %d bytes\n", n);
+#endif
+ sleep(1); /*XXX*/
+#ifdef notdef
+ if (shutdown(so, 2) < 0)
+ syslog(LOG_ERR, "shutdown: %s", strerror(errno));
+#endif
+ /*
+ * Throw away the open file descriptor
+ */
+ (void) close(fd);
+}
+
+void activate(q, so)
+qelem *q;
+int so;
+{
+ struct portal_cred pcred;
+ char key[MAXPATHLEN+1];
+ int error;
+ char **v;
+ int fd = -1;
+
+ /*
+ * Read the key from the socket
+ */
+ error = get_request(so, &pcred, key, sizeof(key));
+ if (error) {
+ syslog(LOG_ERR, "activate: recvmsg: %s", strerror(error));
+ goto drop;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "lookup key %s\n", key);
+#endif
+
+ /*
+ * Find a match in the configuration file
+ */
+ v = conf_match(q, key);
+
+ /*
+ * If a match existed, then find an appropriate portal
+ * otherwise simply return ENOENT.
+ */
+ if (v) {
+ error = activate_argv(&pcred, key, v, so, &fd);
+ if (error)
+ fd = -1;
+ else if (fd < 0)
+ error = -1;
+ } else {
+ error = ENOENT;
+ }
+
+ if (error >= 0)
+ send_reply(so, fd, error);
+
+drop:;
+ close(so);
+}
diff --git a/usr.sbin/mount_portalfs/conf.c b/usr.sbin/mount_portalfs/conf.c
new file mode 100644
index 0000000..18833b6
--- /dev/null
+++ b/usr.sbin/mount_portalfs/conf.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <regexp.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+#define ALLOC(ty) (xmalloc(sizeof(ty)))
+
+typedef struct path path;
+struct path {
+ qelem p_q; /* 2-way linked list */
+ int p_lno; /* Line number of this record */
+ char *p_args; /* copy of arg string (malloc) */
+ char *p_key; /* Pathname to match (also p_argv[0]) */
+ regexp *p_re; /* RE to match against pathname (malloc) */
+ int p_argc; /* number of elements in arg string */
+ char **p_argv; /* argv[] pointers into arg string (malloc) */
+};
+
+static char *conf_file; /* XXX for regerror */
+static path *curp; /* XXX for regerror */
+
+/*
+ * Add an element to a 2-way list,
+ * just after (pred)
+ */
+static 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;
+}
+
+/*
+ * Remove an element from a 2-way list
+ */
+static void rem_que(elem)
+qelem *elem;
+{
+ qelem *p = elem->q_forw;
+ qelem *p2 = elem->q_back;
+ p2->q_forw = p;
+ p->q_back = p2;
+}
+
+/*
+ * Error checking malloc
+ */
+static void *xmalloc(siz)
+unsigned siz;
+{
+ void *p = malloc(siz);
+ if (p)
+ return (p);
+ syslog(LOG_ALERT, "malloc: failed to get %d bytes", siz);
+ exit(1);
+}
+
+/*
+ * Insert the path in the list.
+ * If there is already an element with the same key then
+ * the *second* one is ignored (return 0). If the key is
+ * not found then the path is added to the end of the list
+ * and 1 is returned.
+ */
+static int pinsert(p0, q0)
+path *p0;
+qelem *q0;
+{
+ qelem *q;
+
+ if (p0->p_argc == 0)
+ return (0);
+
+ for (q = q0->q_forw; q != q0; q = q->q_forw) {
+ path *p = (path *) q;
+ if (strcmp(p->p_key, p0->p_key) == 0)
+ return (0);
+ }
+ ins_que(&p0->p_q, q0->q_back);
+ return (1);
+
+}
+
+void regerror(s)
+const char *s;
+{
+ syslog(LOG_ERR, "%s:%s: regcomp %s: %s",
+ conf_file, curp->p_lno, curp->p_key, s);
+}
+
+static path *palloc(cline, lno)
+char *cline;
+int lno;
+{
+ int c;
+ char *s;
+ char *key;
+ path *p;
+ char **ap;
+
+ /*
+ * Implement comment chars
+ */
+ s = strchr(cline, '#');
+ if (s)
+ *s = 0;
+
+ /*
+ * Do a pass through the string to count the number
+ * of arguments
+ */
+ c = 0;
+ key = strdup(cline);
+ for (s = key; s != NULL; ) {
+ char *val;
+ while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
+ ;
+ if (val)
+ c++;
+ }
+ c++;
+ free(key);
+
+ if (c <= 1)
+ return (0);
+
+ /*
+ * Now do another pass and generate a new path structure
+ */
+ p = ALLOC(path);
+ p->p_argc = 0;
+ p->p_argv = xmalloc(c * sizeof(char *));
+ p->p_args = strdup(cline);
+ ap = p->p_argv;
+ for (s = p->p_args; s != NULL; ) {
+ char *val;
+ while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0')
+ ;
+ if (val) {
+ *ap++ = val;
+ p->p_argc++;
+ }
+ }
+ *ap = 0;
+
+#ifdef DEBUG
+ for (c = 0; c < p->p_argc; c++)
+ printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]);
+#endif
+
+ p->p_key = p->p_argv[0];
+ if (strpbrk(p->p_key, RE_CHARS)) {
+ curp = p; /* XXX */
+ p->p_re = regcomp(p->p_key);
+ curp = 0; /* XXX */
+ } else {
+ p->p_re = 0;
+ }
+ p->p_lno = lno;
+
+ return (p);
+}
+
+/*
+ * Free a path structure
+ */
+static void pfree(p)
+path *p;
+{
+ free(p->p_args);
+ if (p->p_re)
+ free((char *) p->p_re);
+ free((char *) p->p_argv);
+ free((char *) p);
+}
+
+/*
+ * Discard all currently held path structures on q0.
+ * and add all the ones on xq.
+ */
+static void preplace(q0, xq)
+qelem *q0;
+qelem *xq;
+{
+ /*
+ * While the list is not empty,
+ * take the first element off the list
+ * and free it.
+ */
+ while (q0->q_forw != q0) {
+ qelem *q = q0->q_forw;
+ rem_que(q);
+ pfree((path *) q);
+ }
+ while (xq->q_forw != xq) {
+ qelem *q = xq->q_forw;
+ rem_que(q);
+ ins_que(q, q0);
+ }
+}
+
+/*
+ * Read the lines from the configuration file and
+ * add them to the list of paths.
+ */
+static void readfp(q0, fp)
+qelem *q0;
+FILE *fp;
+{
+ char cline[LINE_MAX];
+ int nread = 0;
+ qelem q;
+
+ /*
+ * Make a new empty list.
+ */
+ q.q_forw = q.q_back = &q;
+
+ /*
+ * Read the lines from the configuration file.
+ */
+ while (fgets(cline, sizeof(cline), fp)) {
+ path *p = palloc(cline, nread+1);
+ if (p && !pinsert(p, &q))
+ pfree(p);
+ nread++;
+ }
+
+ /*
+ * If some records were read, then throw
+ * away the old list and replace with the
+ * new one.
+ */
+ if (nread)
+ preplace(q0, &q);
+}
+
+/*
+ * Read the configuration file (conf) and replace
+ * the existing path list with the new version.
+ * If the file is not readable, then no changes take place
+ */
+void conf_read(q, conf)
+qelem *q;
+char *conf;
+{
+ FILE *fp = fopen(conf, "r");
+ if (fp) {
+ conf_file = conf; /* XXX */
+ readfp(q, fp);
+ conf_file = 0; /* XXX */
+ (void) fclose(fp);
+ } else {
+ syslog(LOG_ERR, "open config file \"%s\": %s", conf, strerror(errno));
+ }
+}
+
+
+char **conf_match(q0, key)
+qelem *q0;
+char *key;
+{
+ qelem *q;
+
+ for (q = q0->q_forw; q != q0; q = q->q_forw) {
+ path *p = (path *) q;
+ if (p->p_re) {
+ if (regexec(p->p_re, key))
+ return (p->p_argv+1);
+ } else {
+ if (strncmp(p->p_key, key, strlen(p->p_key)) == 0)
+ return (p->p_argv+1);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/mount_portalfs/mount_portalfs.8 b/usr.sbin/mount_portalfs/mount_portalfs.8
new file mode 100644
index 0000000..0df6531
--- /dev/null
+++ b/usr.sbin/mount_portalfs/mount_portalfs.8
@@ -0,0 +1,136 @@
+.\"
+.\" Copyright (c) 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software donated to Berkeley by
+.\" Jan-Simon Pendry.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mount_portal.8 8.3 (Berkeley) 3/27/94
+.\"
+.\"
+.Dd March 27, 1994
+.Dt MOUNT_PORTAL 8
+.Os BSD 4.4
+.Sh NAME
+.Nm mount_portal
+.Nd mount the portal daemon
+.Sh SYNOPSIS
+.Nm mount_portal
+.Op Fl o Ar options
+.Ar /etc/portal.conf
+.Ar mount_point
+.Sh DESCRIPTION
+The
+.Nm mount_portal
+command attaches an instance of the portal daemon
+to the global filesystem namespace.
+The conventional mount point is
+.Pa /p .
+.PA /dev .
+This command is normally executed by
+.Xr mount 8
+at boot time.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl o
+Options are specified with a
+.Fl o
+flag followed by a comma separated string of options.
+See the
+.Xr mount 8
+man page for possible options and their meanings.
+.El
+.Pp
+The portal daemon provides an
+.Em open
+service.
+Objects opened under the portal mount point are
+dynamically created by the portal daemon according
+to rules specified in the named configuration file.
+Using this mechanism allows descriptors such as sockets
+to be made available in the filesystem namespace.
+.Pp
+The portal daemon works by being passed the full pathname
+of the object being opened.
+The daemon creates an appropriate descriptor according
+to the rules in the configuration file, and then passes the descriptor back
+to the calling process as the result of the open system call.
+.Sh NAMESPACE
+By convention, the portal daemon divides the namespace into sub-namespaces,
+each of which handles objects of a particular type.
+.Pp
+Currently, two sub-namespaces are implemented:
+.Pa tcp
+and
+.Pa fs .
+The
+.Pa tcp
+namespace takes a hostname and a port (slash separated) and
+creates an open TCP/IP connection.
+The
+.Pa fs
+namespace opens the named file, starting back at the root directory.
+This can be used to provide a controlled escape path from
+a chrooted environment.
+.Sh "CONFIGURATION FILE"
+The configuration file contains a list of rules.
+Each rule takes one line and consists of two or more
+whitespace separated fields.
+A hash (``#'') character causes the remainder of a line to
+be ignored. Blank lines are ignored.
+.Pp
+The first field is a pathname prefix to match
+against the requested pathname.
+If a match is found, the second field
+tells the daemon what type of object to create.
+Subsequent fields are passed to the creation function.
+.Bd -literal
+# @(#)portal.conf 5.1 (Berkeley) 7/13/92
+tcp/ tcp tcp/
+fs/ file fs/
+.Ed
+.Sh FILES
+.Bl -tag -width /p/* -compact
+.It Pa /p/*
+.El
+.Sh SEE ALSO
+.Xr mount 2 ,
+.Xr unmount 2 ,
+.Xr fstab 5 ,
+.Xr mount 8
+.Sh CAVEATS
+This filesystem may not be NFS-exported.
+.Sh HISTORY
+The
+.Nm mount_portal
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/mount_portalfs/mount_portalfs.c b/usr.sbin/mount_portalfs/mount_portalfs.c
new file mode 100644
index 0000000..d88a38d
--- /dev/null
+++ b/usr.sbin/mount_portalfs/mount_portalfs.c
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 1992, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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) 1992, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mount_portal.c 8.4 (Berkeley) 3/27/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/syslog.h>
+#include <sys/mount.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mntopts.h"
+#include "pathnames.h"
+#include "portald.h"
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ { NULL }
+};
+
+static void usage __P((void));
+
+static sig_atomic_t readcf; /* Set when SIGHUP received */
+
+static void sigchld(sig)
+int sig;
+{
+ pid_t pid;
+
+ while ((pid = waitpid((pid_t) -1, (int *) 0, WNOHANG)) > 0)
+ ;
+ if (pid < 0)
+ syslog(LOG_WARNING, "waitpid: %s", strerror(errno));
+}
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct portal_args args;
+ struct sockaddr_un un;
+ char *conf;
+ char *mountpt;
+ int mntflags = 0;
+ char tag[32];
+ struct vfsconf *vfc;
+
+ qelem q;
+ int rc;
+ int so;
+ int error = 0;
+
+ /*
+ * Crack command line args
+ */
+ int ch;
+
+ while ((ch = getopt(argc, argv, "o:")) != EOF) {
+ switch (ch) {
+ case 'o':
+ getmntopts(optarg, mopts, &mntflags);
+ break;
+ default:
+ error = 1;
+ break;
+ }
+ }
+
+ if (optind != (argc - 2))
+ error = 1;
+
+ if (error)
+ usage();
+
+ /*
+ * Get config file and mount point
+ */
+ conf = argv[optind];
+ mountpt = argv[optind+1];
+
+ /*
+ * Construct the listening socket
+ */
+ un.sun_family = AF_UNIX;
+ if (sizeof(_PATH_TMPPORTAL) >= sizeof(un.sun_path)) {
+ fprintf(stderr, "mount_portal: portal socket name too long\n");
+ exit(1);
+ }
+ strcpy(un.sun_path, _PATH_TMPPORTAL);
+ mktemp(un.sun_path);
+ un.sun_len = strlen(un.sun_path);
+
+ so = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (so < 0) {
+ fprintf(stderr, "mount_portal: socket: %s\n", strerror(errno));
+ exit(1);
+ }
+ (void) unlink(un.sun_path);
+ if (bind(so, (struct sockaddr *) &un, sizeof(un)) < 0)
+ err(1, NULL);
+ (void) unlink(un.sun_path);
+
+ (void) listen(so, 5);
+
+ args.pa_socket = so;
+ sprintf(tag, "portal:%d", getpid());
+ args.pa_config = tag;
+
+ vfc = getvfsbyname("portal");
+ if(!vfc && vfsisloadable("portal")) {
+ if(vfsload("portal"))
+ err(1, "vfsload(portal)");
+ endvfsent(); /* flush cache */
+ vfc = getvfsbyname("portal");
+ }
+
+ rc = mount(vfc ? vfc->vfc_index : MOUNT_PORTAL, mountpt, mntflags, &args);
+ if (rc < 0)
+ err(1, NULL);
+
+#ifdef notdef
+ /*
+ * Everything is ready to go - now is a good time to fork
+ */
+ daemon(0, 0);
+#endif
+
+ /*
+ * Start logging (and change name)
+ */
+ openlog("portald", LOG_CONS|LOG_PID, LOG_DAEMON);
+
+ q.q_forw = q.q_back = &q;
+ readcf = 1;
+
+ signal(SIGCHLD, sigchld);
+
+ /*
+ * Just loop waiting for new connections and activating them
+ */
+ for (;;) {
+ struct sockaddr_un un2;
+ int len2 = sizeof(un2);
+ int so2;
+ pid_t pid;
+ fd_set fdset;
+ int rc;
+
+ /*
+ * Check whether we need to re-read the configuration file
+ */
+ if (readcf) {
+ readcf = 0;
+ conf_read(&q, conf);
+ continue;
+ }
+
+ /*
+ * Accept a new connection
+ * Will get EINTR if a signal has arrived, so just
+ * ignore that error code
+ */
+ FD_SET(so, &fdset);
+ rc = select(so+1, &fdset, (void *) 0, (void *) 0, (void *) 0);
+ if (rc < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %s", strerror(errno));
+ exit(1);
+ }
+ if (rc == 0)
+ break;
+ so2 = accept(so, (struct sockaddr *) &un2, &len2);
+ if (so2 < 0) {
+ /*
+ * The unmount function does a shutdown on the socket
+ * which will generated ECONNABORTED on the accept.
+ */
+ if (errno == ECONNABORTED)
+ break;
+ if (errno != EINTR) {
+ syslog(LOG_ERR, "accept: %s", strerror(errno));
+ exit(1);
+ }
+ continue;
+ }
+
+ /*
+ * Now fork a new child to deal with the connection
+ */
+ eagain:;
+ switch (pid = fork()) {
+ case -1:
+ if (errno == EAGAIN) {
+ sleep(1);
+ goto eagain;
+ }
+ syslog(LOG_ERR, "fork: %s", strerror(errno));
+ break;
+ case 0:
+ (void) close(so);
+ activate(&q, so2);
+ break;
+ default:
+ (void) close(so2);
+ break;
+ }
+ }
+ syslog(LOG_INFO, "%s unmounted", mountpt);
+ exit(0);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: mount_portal [-o options] config mount-point\n");
+ exit(1);
+}
diff --git a/usr.sbin/mount_portalfs/pathnames.h b/usr.sbin/mount_portalfs/pathnames.h
new file mode 100644
index 0000000..2532114
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pathnames.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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/5/93
+ *
+ * $Id: pathnames.h,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <paths.h>
+
+#define _PATH_TMPPORTAL "/tmp/portalXXXXXX" /* Scratch socket name */
diff --git a/usr.sbin/mount_portalfs/portal.conf b/usr.sbin/mount_portalfs/portal.conf
new file mode 100644
index 0000000..5b5a773
--- /dev/null
+++ b/usr.sbin/mount_portalfs/portal.conf
@@ -0,0 +1,7 @@
+# @(#)portal.conf 8.1 (Berkeley) 6/5/93
+# $Id: portal.conf,v 1.1 1992/05/27 06:50:13 jsp Exp jsp $
+tcplisten/ tcplisten tcplisten/
+tcp/ tcp tcp/
+fs/ file fs/
+pipe/ pipe
+foo/ exec ./bar bar baz
diff --git a/usr.sbin/mount_portalfs/portald.h b/usr.sbin/mount_portalfs/portald.h
new file mode 100644
index 0000000..fbe111b
--- /dev/null
+++ b/usr.sbin/mount_portalfs/portald.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)portald.h 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: portald.h,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <sys/cdefs.h>
+#include <miscfs/portal/portal.h>
+
+/*
+ * Meta-chars in an RE. Paths in the config file containing
+ * any of these characters will be matched using regexec, other
+ * paths will be prefix-matched.
+ */
+#define RE_CHARS ".|()[]*+?\\^$"
+
+typedef struct qelem qelem;
+
+struct qelem {
+ qelem *q_forw;
+ qelem *q_back;
+};
+
+typedef struct provider provider;
+struct provider {
+ char *pr_match;
+ int (*pr_func) __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+};
+extern provider providers[];
+
+/*
+ * Portal providers
+ */
+extern int portal_exec __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+extern int portal_file __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+extern int portal_tcp __P((struct portal_cred *,
+ char *key, char **v, int so, int *fdp));
+
+/*
+ * Global functions
+ */
+extern void activate __P((qelem *q, int so));
+extern char **conf_match __P((qelem *q, char *key));
+extern void conf_read __P((qelem *q, char *conf));
diff --git a/usr.sbin/mount_portalfs/pt_conf.c b/usr.sbin/mount_portalfs/pt_conf.c
new file mode 100644
index 0000000..d1eba94
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_conf.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pt_conf.c 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: pt_conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp jsp $
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include "portald.h"
+
+provider providers[] = {
+ { "exec", portal_exec },
+ { "file", portal_file },
+ { "tcp", portal_tcp },
+ { 0, 0 }
+};
diff --git a/usr.sbin/mount_portalfs/pt_exec.c b/usr.sbin/mount_portalfs/pt_exec.c
new file mode 100644
index 0000000..06e3382
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_exec.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pt_exec.c 8.1 (Berkeley) 6/5/93
+ *
+ * $Id: pt_exec.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+int portal_exec(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ return (ENOEXEC);
+}
+
diff --git a/usr.sbin/mount_portalfs/pt_file.c b/usr.sbin/mount_portalfs/pt_file.c
new file mode 100644
index 0000000..929f261
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_file.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pt_file.c 8.2 (Berkeley) 3/27/94
+ *
+ * $Id: pt_file.c,v 1.1.1.1 1994/05/26 06:34:34 rgrimes Exp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+
+#include "portald.h"
+
+int portal_file(pcr, key, v, so, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int so;
+int *fdp;
+{
+ int fd;
+ char pbuf[MAXPATHLEN];
+ int error;
+ gid_t gidset[NGROUPS];
+ int i;
+
+ pbuf[0] = '/';
+ strcpy(pbuf+1, key + (v[1] ? strlen(v[1]) : 0));
+
+#ifdef DEBUG
+ printf("path = %s, uid = %d, gid = %d\n", pbuf, pcr->pcr_uid, pcr->pcr_groups[0]);
+#endif
+
+ for (i = 0; i < pcr->pcr_ngroups; i++)
+ gidset[i] = pcr->pcr_groups[i];
+
+ if (setgroups(pcr->pcr_ngroups, gidset) < 0)
+ return (errno);
+
+ if (seteuid(pcr->pcr_uid) < 0)
+ return (errno);
+
+ fd = open(pbuf, O_RDWR|O_CREAT, 0666);
+ if (fd < 0)
+ error = errno;
+ else
+ error = 0;
+
+ if (seteuid((uid_t) 0) < 0) { /* XXX - should reset gidset too */
+ error = errno;
+ syslog(LOG_ERR, "setcred: %s", strerror(error));
+ if (fd >= 0) {
+ (void) close(fd);
+ fd = -1;
+ }
+ }
+
+ if (error == 0)
+ *fdp = fd;
+
+#ifdef DEBUG
+ fprintf(stderr, "pt_file returns *fdp = %d, error = %d\n", *fdp, error);
+#endif
+
+ return (error);
+}
diff --git a/usr.sbin/mount_portalfs/pt_tcp.c b/usr.sbin/mount_portalfs/pt_tcp.c
new file mode 100644
index 0000000..18a53ce
--- /dev/null
+++ b/usr.sbin/mount_portalfs/pt_tcp.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ * All rights reserved.
+ *
+ * This code is derived from software donated to Berkeley by
+ * Jan-Simon Pendry.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pt_tcp.c 8.3 (Berkeley) 3/27/94
+ *
+ * $Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "portald.h"
+
+/*
+ * Key will be tcp/host/port[/"priv"]
+ * Create a TCP socket connected to the
+ * requested host and port.
+ * Some trailing suffix values have special meanings.
+ * An unrecognised suffix is an error.
+ */
+int portal_tcp(pcr, key, v, kso, fdp)
+struct portal_cred *pcr;
+char *key;
+char **v;
+int kso;
+int *fdp;
+{
+ char host[MAXHOSTNAMELEN];
+ char port[MAXHOSTNAMELEN];
+ char *p = key + (v[1] ? strlen(v[1]) : 0);
+ char *q;
+ struct hostent *hp;
+ struct servent *sp;
+ struct in_addr **ipp;
+ struct in_addr *ip[2];
+ struct in_addr ina;
+ int s_port;
+ int priv = 0;
+ struct sockaddr_in sain;
+
+ q = strchr(p, '/');
+ if (q == 0 || q - p >= sizeof(host))
+ return (EINVAL);
+ *q = '\0';
+ strcpy(host, p);
+ p = q + 1;
+
+ q = strchr(p, '/');
+ if (q)
+ *q = '\0';
+ if (strlen(p) >= sizeof(port))
+ return (EINVAL);
+ strcpy(port, p);
+ if (q) {
+ p = q + 1;
+ if (strcmp(p, "priv") == 0) {
+ if (pcr->pcr_uid == 0)
+ priv = 1;
+ else
+ return (EPERM);
+ } else {
+ return (EINVAL);
+ }
+ }
+
+ hp = gethostbyname(host);
+ if (hp != 0) {
+ ipp = (struct in_addr **) hp->h_addr_list;
+ } else {
+ ina.s_addr = inet_addr(host);
+ if (ina.s_addr == INADDR_NONE)
+ return (EINVAL);
+ ip[0] = &ina;
+ ip[1] = 0;
+ ipp = ip;
+ }
+
+ sp = getservbyname(port, "tcp");
+ if (sp != 0)
+ s_port = sp->s_port;
+ else {
+ s_port = atoi(port);
+ if (s_port == 0)
+ return (EINVAL);
+ }
+
+ bzero(&sain, sizeof(sain));
+ sain.sin_len = sizeof(sain);
+ sain.sin_family = AF_INET;
+ sain.sin_port = s_port;
+
+ while (ipp[0]) {
+ int so;
+
+ if (priv)
+ so = rresvport((int *) 0);
+ else
+ so = socket(AF_INET, SOCK_STREAM, 0);
+ if (so < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ return (errno);
+ }
+
+ sain.sin_addr = *ipp[0];
+ if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
+ *fdp = so;
+ return (0);
+ }
+ (void) close(so);
+
+ ipp++;
+ }
+
+ return (errno);
+}
diff --git a/usr.sbin/mountd/Makefile b/usr.sbin/mountd/Makefile
new file mode 100644
index 0000000..f32e11b
--- /dev/null
+++ b/usr.sbin/mountd/Makefile
@@ -0,0 +1,9 @@
+# From: @(#)Makefile 8.3 (Berkeley) 1/25/94
+# $Id$
+
+PROG= mountd
+CFLAGS+=-DNFS -DMFS -DCD9660 -DMSDOSFS
+MAN5= exports.5 netgroup.5
+MAN8= mountd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mountd/exports.5 b/usr.sbin/mountd/exports.5
new file mode 100644
index 0000000..d32527f
--- /dev/null
+++ b/usr.sbin/mountd/exports.5
@@ -0,0 +1,250 @@
+.\" 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.
+.\"
+.\" @(#)exports.5 8.2 (Berkeley) 1/28/94
+.\"
+.Dd January 28, 1994
+.Dt EXPORTS 5
+.Os
+.Sh NAME
+.Nm exports
+.Nd define remote mount points for
+.Tn NFS
+mount requests
+.Sh SYNOPSIS
+.Nm exports
+.Sh DESCRIPTION
+The
+.Nm exports
+file specifies remote mount points for the
+.Tn NFS
+mount protocol per the
+.Tn NFS
+server specification; see
+.%T "Network File System Protocol Specification \\*(tNRFC\\*(sP 1094, Appendix A" .
+.Pp
+Each line in the file
+(other than comment lines that begin with a #)
+specifies the mount point(s) and export flags within one local server
+filesystem for one or more hosts.
+A host may be specified only once for each local filesystem on the
+server and there may be only one default entry for each server
+filesystem that applies to all other hosts.
+The latter exports the filesystem to the ``world'' and should
+be used only when the filesystem contains public information.
+.Pp
+In a mount entry,
+the first field(s) specify the directory path(s) within a server filesystem
+that can be mounted on by the corresponding client(s).
+There are two forms of this specification.
+The first is to list all mount points as absolute
+directory paths separated by whitespace.
+The second is to specify the pathname of the root of the filesystem
+followed by the
+.Fl alldirs
+flag;
+this form allows the host(s) to mount any directory within the filesystem.
+The pathnames must not have any symbolic links in them and should not have
+any "." or ".." components.
+Mount points for a filesystem may appear on multiple lines each with
+different sets of hosts and export options.
+.Pp
+The second component of a line specifies how the filesystem is to be
+exported to the host set.
+The option flags specify whether the filesystem
+is exported read-only or read-write and how the client uid is mapped to
+user credentials on the server.
+.Pp
+Export options are specified as follows:
+.Pp
+.Sm off
+.Fl maproot No = Sy user
+.Sm on
+The credential of the specified user is used for remote access by root.
+The credential includes all the groups to which the user is a member
+on the local machine (see
+.Xr id 1 ).
+The user may be specified by name or number.
+.Pp
+.Sm off
+.Fl maproot No = Sy user:group1:group2:...
+.Sm on
+The colon separated list is used to specify the precise credential
+to be used for remote access by root.
+The elements of the list may be either names or numbers.
+Note that user: should be used to distinguish a credential containing
+no groups from a complete credential for that user.
+.Pp
+.Sm off
+.Fl mapall No = Sy user
+.Sm on
+or
+.Sm off
+.Fl mapall No = Sy user:group1:group2:...
+.Sm on
+specifies a mapping for all client uids (including root)
+using the same semantics as
+.Fl maproot .
+.Pp
+The option
+.Fl r
+is a synonym for
+.Fl maproot
+in an effort to be backward compatible with older export file formats.
+.Pp
+In the absence of
+.Fl maproot
+and
+.Fl mapall
+options, remote accesses by root will result in using a credential of -2:-2.
+All other users will be mapped to their remote credential.
+If a
+.Fl maproot
+option is given,
+remote access by root will be mapped to that credential instead of -2:-2.
+If a
+.Fl mapall
+option is given,
+all users (including root) will be mapped to that credential in
+place of their own.
+.Pp
+The
+.Fl kerb
+option specifies that the Kerberos authentication server should be
+used to authenticate and map client credentials.
+(Note that this is NOT Sun NFS compatible and
+is supported for TCP transport only.)
+.Pp
+The
+.Fl ro
+option specifies that the filesystem should be exported read-only
+(default read/write).
+The option
+.Fl o
+is a synonym for
+.Fl ro
+in an effort to be backward compatible with older export file formats.
+.Pp
+The third component of a line specifies the host set to which the line applies.
+The set may be specified in three ways.
+The first way is to list the host name(s) separated by white space.
+(Standard internet ``dot'' addresses may be used in place of names.)
+The second way is to specify a ``netgroup'' as defined in the netgroup file (see
+.Xr netgroup 5 ).
+The third way is to specify an internet subnetwork using a network and
+network mask that is defined as the set of all hosts with addresses within
+the subnetwork.
+This latter approach requires less overhead within the
+kernel and is recommended for cases where the export line refers to a
+large number of clients within an administrative subnet.
+.Pp
+The first two cases are specified by simply listing the name(s) separated
+by whitespace.
+All names are checked to see if they are ``netgroup'' names
+first and are assumed to be hostnames otherwise.
+Using the full domain specification for a hostname can normally
+circumvent the problem of a host that has the same name as a netgroup.
+The third case is specified by the flag
+.Sm off
+.Fl network No = Sy netname
+.Sm on
+and optionally
+.Sm off
+.Fl mask No = Sy netmask .
+.Sm on
+If the mask is not specified, it will default to the mask for that network
+class (A, B or C; see
+.Xr inet 5 ).
+.Pp
+For example:
+.Bd -literal -offset indent
+/usr /usr/local -maproot=0:10 friends
+/usr -maproot=daemon grumpy.cis.uoguelph.ca 131.104.48.16
+/usr -ro -mapall=nobody
+/u -maproot=bin: -network 131.104.48 -mask 255.255.255.0
+/u2 -maproot=root friends
+/u2 -alldirs -kerb -network cis-net -mask cis-mask
+.Ed
+.Pp
+Given that
+.Sy /usr ,
+.Sy /u
+and
+.Sy /u2
+are
+local filesystem mount points, the above example specifies the following:
+.Sy /usr
+is exported to hosts
+.Em friends
+where friends is specified in the netgroup file
+with users mapped to their remote credentials and
+root mapped to uid 0 and group 10.
+It is exported read-write and the hosts in ``friends'' can mount either /usr
+or /usr/local.
+It is exported to
+.Em 131.104.48.16
+and
+.Em grumpy.cis.uoguelph.ca
+with users mapped to their remote credentials and
+root mapped to the user and groups associated with ``daemon'';
+it is exported to the rest of the world as read-only with
+all users mapped to the user and groups associated with ``nobody''.
+.Pp
+.Sy /u
+is exported to all hosts on the subnetwork
+.Em 131.104.48
+with root mapped to the uid for ``bin'' and with no group access.
+.Pp
+.Sy /u2
+is exported to the hosts in ``friends'' with root mapped to uid and groups
+associated with ``root'';
+it is exported to all hosts on network ``cis-net'' allowing mounts at any
+directory within /u2 and mapping all uids to credentials for the principal
+that is authenticated by a Kerberos ticket.
+.Sh FILES
+.Bl -tag -width /etc/exports -compact
+.It Pa /etc/exports
+The default remote mount-point file.
+.El
+.Sh SEE ALSO
+.Xr netgroup 5 ,
+.Xr mountd 8 ,
+.Xr nfsd 8 ,
+.Xr showmount 8
+.Sh BUGS
+The export options are tied to the local mount points in the kernel and
+must be non-contradictory for any exported subdirectory of the local
+server mount point.
+It is recommended that all exported directories within the same server
+filesystem be specified on adjacent lines going down the tree.
+You cannot specify a hostname that is also the name of a netgroup.
+Specifying the full domain specification for a hostname can normally
+circumvent the problem.
diff --git a/usr.sbin/mountd/mountd.8 b/usr.sbin/mountd/mountd.8
new file mode 100644
index 0000000..77cb9c9
--- /dev/null
+++ b/usr.sbin/mountd/mountd.8
@@ -0,0 +1,118 @@
+.\" 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: @(#)mountd.8 8.1 (Berkeley) 6/9/93
+.\" $Id$
+.\"
+.Dd September 22, 1994
+.Dt MOUNTD 8
+.Os
+.Sh NAME
+.Nm mountd
+.Nd service remote
+.Tn NFS
+mount requests
+.Sh SYNOPSIS
+.Nm /sbin/mountd
+.Op Fl n
+.Op Ar exportsfile
+.Sh DESCRIPTION
+.Xr Mountd
+is the server for
+.Tn NFS
+mount requests from other client machines.
+.Xr Mountd
+listens for service requests at the port indicated in the
+.Tn NFS
+server specification; see
+.%T "Network File System Protocol Specification" ,
+RFC1094.
+.Pp
+Options and operands available for
+.Nm mountd :
+.Bl -tag -width Ds
+.It Fl n
+The
+.Fl n
+option allows non-root mount requests to be served.
+This should only be specified if there are clients such as PC's,
+that require it.
+.It Ar exportsfile
+The
+.Ar exportsfile
+argument specifies an alternate location
+for the exports file.
+.El
+.Pp
+When mountd is started,
+it loads the export host addresses and options into the kernel
+using the mount(2) system call.
+After changing the exports file,
+a hangup signal should be sent to the mountd daemon
+to get it to reload the export information.
+After sending the SIGHUP
+(kill -HUP `cat /var/run/mountd.pid`),
+check the syslog output to see if mountd logged any parsing
+errors in the exports file.
+.Pp
+If
+.Nm mountd
+detects that the running kernel does not include
+.Tn NFS
+support, it will attempt to load a loadable kernel module containing
+.Tn NFS
+code, using
+.Xr modload 8
+by way of
+.Xr vfsload 3 .
+If this fails, or no
+.Tn NFS
+LKM was available,
+.Nm mountd
+exits with an error.
+.Sh FILES
+.Bl -tag -width /var/run/mountd.pid -compact
+.It Pa /etc/exports
+the list of exported filesystems
+.It Pa /var/run/mountd.pid
+the pid of the currently running mountd
+.El
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr exports 5 ,
+.Xr modload 8 ,
+.Xr nfsd 8 ,
+.Xr portmap 8 ,
+.Xr showmount 8
+.Sh HISTORY
+The
+.Nm mountd
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
new file mode 100644
index 0000000..605e31f
--- /dev/null
+++ b/usr.sbin/mountd/mountd.c
@@ -0,0 +1,2020 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Herb Hasler and 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /*not lint*/
+
+#ifndef lint
+/*static char sccsid[] = "From: @(#)mountd.c 8.8 (Berkeley) 2/20/94";*/
+static const char rcsid[] =
+ "$Id$";
+#endif /*not lint*/
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/syslog.h>
+#include <sys/ucred.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#ifdef ISO
+#include <netiso/iso.h>
+#endif
+#include <nfs/rpcv2.h>
+#include <nfs/nfsv2.h>
+
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <grp.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+#ifdef DEBUG
+#include <stdarg.h>
+#endif
+
+/*
+ * Structures for keeping the mount list and export list
+ */
+struct mountlist {
+ struct mountlist *ml_next;
+ char ml_host[RPCMNT_NAMELEN+1];
+ char ml_dirp[RPCMNT_PATHLEN+1];
+};
+
+struct dirlist {
+ struct dirlist *dp_left;
+ struct dirlist *dp_right;
+ int dp_flag;
+ struct hostlist *dp_hosts; /* List of hosts this dir exported to */
+ char dp_dirp[1]; /* Actually malloc'd to size of dir */
+};
+/* dp_flag bits */
+#define DP_DEFSET 0x1
+
+struct exportlist {
+ struct exportlist *ex_next;
+ struct dirlist *ex_dirl;
+ struct dirlist *ex_defdir;
+ int ex_flag;
+ fsid_t ex_fs;
+ char *ex_fsdir;
+};
+/* ex_flag bits */
+#define EX_LINKED 0x1
+
+struct netmsk {
+ u_long nt_net;
+ u_long nt_mask;
+ char *nt_name;
+};
+
+union grouptypes {
+ struct hostent *gt_hostent;
+ struct netmsk gt_net;
+#ifdef ISO
+ struct sockaddr_iso *gt_isoaddr;
+#endif
+};
+
+struct grouplist {
+ int gr_type;
+ union grouptypes gr_ptr;
+ struct grouplist *gr_next;
+};
+/* Group types */
+#define GT_NULL 0x0
+#define GT_HOST 0x1
+#define GT_NET 0x2
+#define GT_ISO 0x4
+
+struct hostlist {
+ struct grouplist *ht_grp;
+ struct hostlist *ht_next;
+};
+
+/* Global defs */
+char *add_expdir __P((struct dirlist **, char *, int));
+void add_dlist __P((struct dirlist **, struct dirlist *,
+ struct grouplist *));
+void add_mlist __P((char *, char *));
+int check_dirpath __P((char *));
+int check_options __P((struct dirlist *));
+int chk_host __P((struct dirlist *, u_long, int *));
+void del_mlist __P((char *, char *));
+struct dirlist *dirp_search __P((struct dirlist *, char *));
+int do_mount __P((struct exportlist *, struct grouplist *, int,
+ struct ucred *, char *, int, struct statfs *));
+int do_opt __P((char **, char **, struct exportlist *, struct grouplist *,
+ int *, int *, struct ucred *));
+struct exportlist *ex_search __P((fsid_t *));
+struct exportlist *get_exp __P((void));
+void free_dir __P((struct dirlist *));
+void free_exp __P((struct exportlist *));
+void free_grp __P((struct grouplist *));
+void free_host __P((struct hostlist *));
+void get_exportlist __P((void));
+int get_host __P((char *, struct grouplist *));
+struct hostlist *get_ht __P((void));
+int get_line __P((void));
+void get_mountlist __P((void));
+int get_net __P((char *, struct netmsk *, int));
+void getexp_err __P((struct exportlist *, struct grouplist *));
+struct grouplist *get_grp __P((void));
+void hang_dirp __P((struct dirlist *, struct grouplist *,
+ struct exportlist *, int));
+void mntsrv __P((struct svc_req *, SVCXPRT *));
+void nextfield __P((char **, char **));
+void out_of_mem __P((void));
+void parsecred __P((char *, struct ucred *));
+int put_exlist __P((struct dirlist *, XDR *, struct dirlist *, int *));
+int scan_tree __P((struct dirlist *, u_long));
+void send_umntall __P((void));
+int umntall_each __P((caddr_t, struct sockaddr_in *));
+int xdr_dir __P((XDR *, char *));
+int xdr_explist __P((XDR *, caddr_t));
+int xdr_fhs __P((XDR *, nfsv2fh_t *));
+int xdr_mlist __P((XDR *, caddr_t));
+
+/* C library */
+int getnetgrent();
+void endnetgrent();
+void setnetgrent();
+
+#ifdef ISO
+struct iso_addr *iso_addr();
+#endif
+
+struct exportlist *exphead;
+struct mountlist *mlhead;
+struct grouplist *grphead;
+char exname[MAXPATHLEN];
+struct ucred def_anon = {
+ 1,
+ (uid_t) -2,
+ 1,
+ { (gid_t) -2 }
+};
+int root_only = 1;
+int opt_flags;
+/* Bits for above */
+#define OP_MAPROOT 0x01
+#define OP_MAPALL 0x02
+#define OP_KERB 0x04
+#define OP_MASK 0x08
+#define OP_NET 0x10
+#define OP_ISO 0x20
+#define OP_ALLDIRS 0x40
+
+#ifdef DEBUG
+int debug = 1;
+void SYSLOG __P((int, const char *, ...));
+#define syslog SYSLOG
+#else
+int debug = 0;
+#endif
+
+/*
+ * Mountd server for NFS mount protocol as described in:
+ * NFS: Network File System Protocol Specification, RFC1094, Appendix A
+ * The optional arguments are the exports file name
+ * default: _PATH_EXPORTS
+ * and "-n" to allow nonroot mount.
+ */
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ SVCXPRT *transp;
+ int c;
+ struct vfsconf *vfc;
+
+ vfc = getvfsbyname("nfs");
+ if(!vfc && vfsisloadable("nfs")) {
+ if(vfsload("nfs"))
+ err(1, "vfsload(nfs)");
+ endvfsent(); /* flush cache */
+ vfc = getvfsbyname("nfs");
+ }
+ if(!vfc) {
+ errx(1, "NFS support is not available in the running kernel");
+ }
+
+ while ((c = getopt(argc, argv, "n")) != EOF)
+ switch (c) {
+ case 'n':
+ root_only = 0;
+ break;
+ default:
+ fprintf(stderr, "Usage: mountd [-n] [export_file]\n");
+ exit(1);
+ };
+ argc -= optind;
+ argv += optind;
+ grphead = (struct grouplist *)NULL;
+ exphead = (struct exportlist *)NULL;
+ mlhead = (struct mountlist *)NULL;
+ if (argc == 1) {
+ strncpy(exname, *argv, MAXPATHLEN-1);
+ exname[MAXPATHLEN-1] = '\0';
+ } else
+ strcpy(exname, _PATH_EXPORTS);
+ openlog("mountd", LOG_PID, LOG_DAEMON);
+ if (debug)
+ fprintf(stderr,"Getting export list.\n");
+ get_exportlist();
+ if (debug)
+ fprintf(stderr,"Getting mount list.\n");
+ get_mountlist();
+ if (debug)
+ fprintf(stderr,"Here we go.\n");
+ if (debug == 0) {
+ daemon(0, 0);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ }
+ signal(SIGHUP, (void (*) __P((int))) get_exportlist);
+ signal(SIGTERM, (void (*) __P((int))) send_umntall);
+ { FILE *pidfile = fopen(_PATH_MOUNTDPID, "w");
+ if (pidfile != NULL) {
+ fprintf(pidfile, "%d\n", getpid());
+ fclose(pidfile);
+ }
+ }
+ if ((transp = svcudp_create(RPC_ANYSOCK)) == NULL) {
+ syslog(LOG_ERR, "Can't create socket");
+ exit(1);
+ }
+ pmap_unset(RPCPROG_MNT, RPCMNT_VER1);
+ if (!svc_register(transp, RPCPROG_MNT, RPCMNT_VER1, mntsrv,
+ IPPROTO_UDP)) {
+ syslog(LOG_ERR, "Can't register mount");
+ exit(1);
+ }
+ svc_run();
+ syslog(LOG_ERR, "Mountd died");
+ exit(1);
+}
+
+/*
+ * The mount rpc service
+ */
+void
+mntsrv(rqstp, transp)
+ struct svc_req *rqstp;
+ SVCXPRT *transp;
+{
+ struct exportlist *ep;
+ struct dirlist *dp;
+ nfsv2fh_t nfh;
+ struct authunix_parms *ucr;
+ struct stat stb;
+ struct statfs fsb;
+ struct hostent *hp;
+ u_long saddr;
+ char rpcpath[RPCMNT_PATHLEN+1], dirpath[MAXPATHLEN];
+ int bad = ENOENT, omask, defset;
+ uid_t uid = -2;
+
+ /* Get authorization */
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_UNIX:
+ ucr = (struct authunix_parms *)rqstp->rq_clntcred;
+ uid = ucr->aup_uid;
+ break;
+ case AUTH_NULL:
+ default:
+ break;
+ }
+
+ saddr = transp->xp_raddr.sin_addr.s_addr;
+ hp = (struct hostent *)NULL;
+ switch (rqstp->rq_proc) {
+ case NULLPROC:
+ if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
+ syslog(LOG_ERR, "Can't send reply");
+ return;
+ case RPCMNT_MOUNT:
+ if ((uid != 0 && root_only) || uid == -2) {
+ svcerr_weakauth(transp);
+ return;
+ }
+ if (!svc_getargs(transp, xdr_dir, rpcpath)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ /*
+ * Get the real pathname and make sure it is a directory
+ * that exists.
+ */
+ if (realpath(rpcpath, dirpath) == 0 ||
+ stat(dirpath, &stb) < 0 ||
+ (stb.st_mode & S_IFMT) != S_IFDIR ||
+ statfs(dirpath, &fsb) < 0) {
+ chdir("/"); /* Just in case realpath doesn't */
+ if (debug)
+ fprintf(stderr, "stat failed on %s\n", dirpath);
+ if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
+ syslog(LOG_ERR, "Can't send reply");
+ return;
+ }
+
+ /* Check in the exports list */
+ omask = sigblock(sigmask(SIGHUP));
+ ep = ex_search(&fsb.f_fsid);
+ defset = 0;
+ if (ep && (chk_host(ep->ex_defdir, saddr, &defset) ||
+ ((dp = dirp_search(ep->ex_dirl, dirpath)) &&
+ chk_host(dp, saddr, &defset)) ||
+ (defset && scan_tree(ep->ex_defdir, saddr) == 0 &&
+ scan_tree(ep->ex_dirl, saddr) == 0))) {
+ /* Get the file handle */
+ bzero((caddr_t)&nfh, sizeof(nfh));
+ if (getfh(dirpath, (fhandle_t *)&nfh) < 0) {
+ bad = errno;
+ syslog(LOG_ERR, "Can't get fh for %s", dirpath);
+ if (!svc_sendreply(transp, xdr_long,
+ (caddr_t)&bad))
+ syslog(LOG_ERR, "Can't send reply");
+ sigsetmask(omask);
+ return;
+ }
+ if (!svc_sendreply(transp, xdr_fhs, (caddr_t)&nfh))
+ syslog(LOG_ERR, "Can't send reply");
+ if (hp == NULL)
+ hp = gethostbyaddr((caddr_t)&saddr,
+ sizeof(saddr), AF_INET);
+ if (hp)
+ add_mlist(hp->h_name, dirpath);
+ else
+ add_mlist(inet_ntoa(transp->xp_raddr.sin_addr),
+ dirpath);
+ if (debug)
+ fprintf(stderr,"Mount successfull.\n");
+ } else {
+ bad = EACCES;
+ if (!svc_sendreply(transp, xdr_long, (caddr_t)&bad))
+ syslog(LOG_ERR, "Can't send reply");
+ }
+ sigsetmask(omask);
+ return;
+ case RPCMNT_DUMP:
+ if (!svc_sendreply(transp, xdr_mlist, (caddr_t)NULL))
+ syslog(LOG_ERR, "Can't send reply");
+ return;
+ case RPCMNT_UMOUNT:
+ if ((uid != 0 && root_only) || uid == -2) {
+ svcerr_weakauth(transp);
+ return;
+ }
+ if (!svc_getargs(transp, xdr_dir, dirpath)) {
+ svcerr_decode(transp);
+ return;
+ }
+ if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
+ syslog(LOG_ERR, "Can't send reply");
+ hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+ if (hp)
+ del_mlist(hp->h_name, dirpath);
+ del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), dirpath);
+ return;
+ case RPCMNT_UMNTALL:
+ if ((uid != 0 && root_only) || uid == -2) {
+ svcerr_weakauth(transp);
+ return;
+ }
+ if (!svc_sendreply(transp, xdr_void, (caddr_t)NULL))
+ syslog(LOG_ERR, "Can't send reply");
+ hp = gethostbyaddr((caddr_t)&saddr, sizeof(saddr), AF_INET);
+ if (hp)
+ del_mlist(hp->h_name, (char *)NULL);
+ del_mlist(inet_ntoa(transp->xp_raddr.sin_addr), (char *)NULL);
+ return;
+ case RPCMNT_EXPORT:
+ if (!svc_sendreply(transp, xdr_explist, (caddr_t)NULL))
+ syslog(LOG_ERR, "Can't send reply");
+ return;
+ default:
+ svcerr_noproc(transp);
+ return;
+ }
+}
+
+/*
+ * Xdr conversion for a dirpath string
+ */
+int
+xdr_dir(xdrsp, dirp)
+ XDR *xdrsp;
+ char *dirp;
+{
+ return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
+}
+
+/*
+ * Xdr routine to generate fhstatus
+ */
+int
+xdr_fhs(xdrsp, nfh)
+ XDR *xdrsp;
+ nfsv2fh_t *nfh;
+{
+ int ok = 0;
+
+ if (!xdr_long(xdrsp, &ok))
+ return (0);
+ return (xdr_opaque(xdrsp, (caddr_t)nfh, NFSX_FH));
+}
+
+int
+xdr_mlist(xdrsp, cp)
+ XDR *xdrsp;
+ caddr_t cp;
+{
+ struct mountlist *mlp;
+ int true = 1;
+ int false = 0;
+ char *strp;
+
+ mlp = mlhead;
+ while (mlp) {
+ if (!xdr_bool(xdrsp, &true))
+ return (0);
+ strp = &mlp->ml_host[0];
+ if (!xdr_string(xdrsp, &strp, RPCMNT_NAMELEN))
+ return (0);
+ strp = &mlp->ml_dirp[0];
+ if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
+ return (0);
+ mlp = mlp->ml_next;
+ }
+ if (!xdr_bool(xdrsp, &false))
+ return (0);
+ return (1);
+}
+
+/*
+ * Xdr conversion for export list
+ */
+int
+xdr_explist(xdrsp, cp)
+ XDR *xdrsp;
+ caddr_t cp;
+{
+ struct exportlist *ep;
+ int false = 0;
+ int omask, putdef;
+
+ omask = sigblock(sigmask(SIGHUP));
+ ep = exphead;
+ while (ep) {
+ putdef = 0;
+ if (put_exlist(ep->ex_dirl, xdrsp, ep->ex_defdir, &putdef))
+ goto errout;
+ if (ep->ex_defdir && putdef == 0 &&
+ put_exlist(ep->ex_defdir, xdrsp, (struct dirlist *)NULL,
+ &putdef))
+ goto errout;
+ ep = ep->ex_next;
+ }
+ sigsetmask(omask);
+ if (!xdr_bool(xdrsp, &false))
+ return (0);
+ return (1);
+errout:
+ sigsetmask(omask);
+ return (0);
+}
+
+/*
+ * Called from xdr_explist() to traverse the tree and export the
+ * directory paths.
+ */
+int
+put_exlist(dp, xdrsp, adp, putdefp)
+ struct dirlist *dp;
+ XDR *xdrsp;
+ struct dirlist *adp;
+ int *putdefp;
+{
+ struct grouplist *grp;
+ struct hostlist *hp;
+ int true = 1;
+ int false = 0;
+ int gotalldir = 0;
+ char *strp;
+
+ if (dp) {
+ if (put_exlist(dp->dp_left, xdrsp, adp, putdefp))
+ return (1);
+ if (!xdr_bool(xdrsp, &true))
+ return (1);
+ strp = dp->dp_dirp;
+ if (!xdr_string(xdrsp, &strp, RPCMNT_PATHLEN))
+ return (1);
+ if (adp && !strcmp(dp->dp_dirp, adp->dp_dirp)) {
+ gotalldir = 1;
+ *putdefp = 1;
+ }
+ if ((dp->dp_flag & DP_DEFSET) == 0 &&
+ (gotalldir == 0 || (adp->dp_flag & DP_DEFSET) == 0)) {
+ hp = dp->dp_hosts;
+ while (hp) {
+ grp = hp->ht_grp;
+ if (grp->gr_type == GT_HOST) {
+ if (!xdr_bool(xdrsp, &true))
+ return (1);
+ strp = grp->gr_ptr.gt_hostent->h_name;
+ if (!xdr_string(xdrsp, &strp,
+ RPCMNT_NAMELEN))
+ return (1);
+ } else if (grp->gr_type == GT_NET) {
+ if (!xdr_bool(xdrsp, &true))
+ return (1);
+ strp = grp->gr_ptr.gt_net.nt_name;
+ if (!xdr_string(xdrsp, &strp,
+ RPCMNT_NAMELEN))
+ return (1);
+ }
+ hp = hp->ht_next;
+ if (gotalldir && hp == (struct hostlist *)NULL) {
+ hp = adp->dp_hosts;
+ gotalldir = 0;
+ }
+ }
+ }
+ if (!xdr_bool(xdrsp, &false))
+ return (1);
+ if (put_exlist(dp->dp_right, xdrsp, adp, putdefp))
+ return (1);
+ }
+ return (0);
+}
+
+#define LINESIZ 10240
+char line[LINESIZ];
+FILE *exp_file;
+
+/*
+ * Get the export list
+ */
+void
+get_exportlist()
+{
+ struct exportlist *ep, *ep2;
+ struct grouplist *grp, *tgrp;
+ struct exportlist **epp;
+ struct dirlist *dirhead;
+ struct statfs fsb, *fsp;
+ struct hostent *hpe;
+ struct ucred anon;
+ char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
+ int len, has_host, exflags, got_nondir, dirplen, num, i, netgrp;
+
+ /*
+ * First, get rid of the old list
+ */
+ ep = exphead;
+ while (ep) {
+ ep2 = ep;
+ ep = ep->ex_next;
+ free_exp(ep2);
+ }
+ exphead = (struct exportlist *)NULL;
+
+ grp = grphead;
+ while (grp) {
+ tgrp = grp;
+ grp = grp->gr_next;
+ free_grp(tgrp);
+ }
+ grphead = (struct grouplist *)NULL;
+
+ /*
+ * And delete exports that are in the kernel for all local
+ * file systems.
+ * XXX: Should know how to handle all local exportable file systems
+ * instead of just MOUNT_UFS.
+ */
+ num = getmntinfo(&fsp, MNT_NOWAIT);
+ for (i = 0; i < num; i++) {
+ union {
+ struct ufs_args ua;
+ struct iso_args ia;
+ struct mfs_args ma;
+ } targs;
+
+ switch (fsp->f_type) {
+ case MOUNT_MFS:
+ case MOUNT_UFS:
+ case MOUNT_CD9660:
+ case MOUNT_MSDOS:
+ targs.ua.fspec = NULL;
+ targs.ua.export.ex_flags = MNT_DELEXPORT;
+ if (mount(fsp->f_type, fsp->f_mntonname,
+ fsp->f_flags | MNT_UPDATE,
+ (caddr_t)&targs) < 0)
+ syslog(LOG_ERR, "Can't delete exports for %s",
+ fsp->f_mntonname);
+ }
+ fsp++;
+ }
+
+ /*
+ * Read in the exports file and build the list, calling
+ * mount() as we go along to push the export rules into the kernel.
+ */
+ if ((exp_file = fopen(exname, "r")) == NULL) {
+ syslog(LOG_ERR, "Can't open %s", exname);
+ exit(2);
+ }
+ dirhead = (struct dirlist *)NULL;
+ while (get_line()) {
+ if (debug)
+ fprintf(stderr,"Got line %s\n",line);
+ cp = line;
+ nextfield(&cp, &endcp);
+ if (*cp == '#')
+ goto nextline;
+
+ /*
+ * Set defaults.
+ */
+ has_host = FALSE;
+ anon = def_anon;
+ exflags = MNT_EXPORTED;
+ got_nondir = 0;
+ opt_flags = 0;
+ ep = (struct exportlist *)NULL;
+
+ /*
+ * Create new exports list entry
+ */
+ len = endcp-cp;
+ tgrp = grp = get_grp();
+ while (len > 0) {
+ if (len > RPCMNT_NAMELEN) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ if (*cp == '-') {
+ if (ep == (struct exportlist *)NULL) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ if (debug)
+ fprintf(stderr, "doing opt %s\n", cp);
+ got_nondir = 1;
+ if (do_opt(&cp, &endcp, ep, grp, &has_host,
+ &exflags, &anon)) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ } else if (*cp == '/') {
+ savedc = *endcp;
+ *endcp = '\0';
+ if (check_dirpath(cp) &&
+ statfs(cp, &fsb) >= 0) {
+ if (got_nondir) {
+ syslog(LOG_ERR, "Dirs must be first");
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ if (ep) {
+ if (ep->ex_fs.val[0] != fsb.f_fsid.val[0] ||
+ ep->ex_fs.val[1] != fsb.f_fsid.val[1]) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ } else {
+ /*
+ * See if this directory is already
+ * in the list.
+ */
+ ep = ex_search(&fsb.f_fsid);
+ if (ep == (struct exportlist *)NULL) {
+ ep = get_exp();
+ ep->ex_fs = fsb.f_fsid;
+ ep->ex_fsdir = (char *)
+ malloc(strlen(fsb.f_mntonname) + 1);
+ if (ep->ex_fsdir)
+ strcpy(ep->ex_fsdir,
+ fsb.f_mntonname);
+ else
+ out_of_mem();
+ if (debug)
+ fprintf(stderr,
+ "Making new ep fs=0x%x,0x%x\n",
+ fsb.f_fsid.val[0],
+ fsb.f_fsid.val[1]);
+ } else if (debug)
+ fprintf(stderr,
+ "Found ep fs=0x%x,0x%x\n",
+ fsb.f_fsid.val[0],
+ fsb.f_fsid.val[1]);
+ }
+
+ /*
+ * Add dirpath to export mount point.
+ */
+ dirp = add_expdir(&dirhead, cp, len);
+ dirplen = len;
+ } else {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ *endcp = savedc;
+ } else {
+ savedc = *endcp;
+ *endcp = '\0';
+ got_nondir = 1;
+ if (ep == (struct exportlist *)NULL) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+
+ /*
+ * Get the host or netgroup.
+ */
+ setnetgrent(cp);
+ netgrp = getnetgrent(&hst, &usr, &dom);
+ do {
+ if (has_host) {
+ grp->gr_next = get_grp();
+ grp = grp->gr_next;
+ }
+ if (netgrp) {
+ if (get_host(hst, grp)) {
+ syslog(LOG_ERR, "Bad netgroup %s", cp);
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ } else if (get_host(cp, grp)) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ has_host = TRUE;
+ } while (netgrp && getnetgrent(&hst, &usr, &dom));
+ endnetgrent();
+ *endcp = savedc;
+ }
+ cp = endcp;
+ nextfield(&cp, &endcp);
+ len = endcp - cp;
+ }
+ if (check_options(dirhead)) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ if (!has_host) {
+ grp->gr_type = GT_HOST;
+ if (debug)
+ fprintf(stderr,"Adding a default entry\n");
+ /* add a default group and make the grp list NULL */
+ hpe = (struct hostent *)malloc(sizeof(struct hostent));
+ if (hpe == (struct hostent *)NULL)
+ out_of_mem();
+ hpe->h_name = "Default";
+ hpe->h_addrtype = AF_INET;
+ hpe->h_length = sizeof (u_long);
+ hpe->h_addr_list = (char **)NULL;
+ grp->gr_ptr.gt_hostent = hpe;
+
+ /*
+ * Don't allow a network export coincide with a list of
+ * host(s) on the same line.
+ */
+ } else if ((opt_flags & OP_NET) && tgrp->gr_next) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+
+ /*
+ * Loop through hosts, pushing the exports into the kernel.
+ * After loop, tgrp points to the start of the list and
+ * grp points to the last entry in the list.
+ */
+ grp = tgrp;
+ do {
+ if (do_mount(ep, grp, exflags, &anon, dirp,
+ dirplen, &fsb)) {
+ getexp_err(ep, tgrp);
+ goto nextline;
+ }
+ } while (grp->gr_next && (grp = grp->gr_next));
+
+ /*
+ * Success. Update the data structures.
+ */
+ if (has_host) {
+ hang_dirp(dirhead, tgrp, ep, (opt_flags & OP_ALLDIRS));
+ grp->gr_next = grphead;
+ grphead = tgrp;
+ } else {
+ hang_dirp(dirhead, (struct grouplist *)NULL, ep,
+ (opt_flags & OP_ALLDIRS));
+ free_grp(grp);
+ }
+ dirhead = (struct dirlist *)NULL;
+ if ((ep->ex_flag & EX_LINKED) == 0) {
+ ep2 = exphead;
+ epp = &exphead;
+
+ /*
+ * Insert in the list in alphabetical order.
+ */
+ while (ep2 && strcmp(ep2->ex_fsdir, ep->ex_fsdir) < 0) {
+ epp = &ep2->ex_next;
+ ep2 = ep2->ex_next;
+ }
+ if (ep2)
+ ep->ex_next = ep2;
+ *epp = ep;
+ ep->ex_flag |= EX_LINKED;
+ }
+nextline:
+ if (dirhead) {
+ free_dir(dirhead);
+ dirhead = (struct dirlist *)NULL;
+ }
+ }
+ fclose(exp_file);
+}
+
+/*
+ * Allocate an export list element
+ */
+struct exportlist *
+get_exp()
+{
+ struct exportlist *ep;
+
+ ep = (struct exportlist *)malloc(sizeof (struct exportlist));
+ if (ep == (struct exportlist *)NULL)
+ out_of_mem();
+ bzero((caddr_t)ep, sizeof (struct exportlist));
+ return (ep);
+}
+
+/*
+ * Allocate a group list element
+ */
+struct grouplist *
+get_grp()
+{
+ struct grouplist *gp;
+
+ gp = (struct grouplist *)malloc(sizeof (struct grouplist));
+ if (gp == (struct grouplist *)NULL)
+ out_of_mem();
+ bzero((caddr_t)gp, sizeof (struct grouplist));
+ return (gp);
+}
+
+/*
+ * Clean up upon an error in get_exportlist().
+ */
+void
+getexp_err(ep, grp)
+ struct exportlist *ep;
+ struct grouplist *grp;
+{
+ struct grouplist *tgrp;
+
+ syslog(LOG_ERR, "Bad exports list line %s", line);
+ if (ep && (ep->ex_flag & EX_LINKED) == 0)
+ free_exp(ep);
+ while (grp) {
+ tgrp = grp;
+ grp = grp->gr_next;
+ free_grp(tgrp);
+ }
+}
+
+/*
+ * Search the export list for a matching fs.
+ */
+struct exportlist *
+ex_search(fsid)
+ fsid_t *fsid;
+{
+ struct exportlist *ep;
+
+ ep = exphead;
+ while (ep) {
+ if (ep->ex_fs.val[0] == fsid->val[0] &&
+ ep->ex_fs.val[1] == fsid->val[1])
+ return (ep);
+ ep = ep->ex_next;
+ }
+ return (ep);
+}
+
+/*
+ * Add a directory path to the list.
+ */
+char *
+add_expdir(dpp, cp, len)
+ struct dirlist **dpp;
+ char *cp;
+ int len;
+{
+ struct dirlist *dp;
+
+ dp = (struct dirlist *)malloc(sizeof (struct dirlist) + len);
+ dp->dp_left = *dpp;
+ dp->dp_right = (struct dirlist *)NULL;
+ dp->dp_flag = 0;
+ dp->dp_hosts = (struct hostlist *)NULL;
+ strcpy(dp->dp_dirp, cp);
+ *dpp = dp;
+ return (dp->dp_dirp);
+}
+
+/*
+ * Hang the dir list element off the dirpath binary tree as required
+ * and update the entry for host.
+ */
+void
+hang_dirp(dp, grp, ep, alldirs)
+ struct dirlist *dp;
+ struct grouplist *grp;
+ struct exportlist *ep;
+ int alldirs;
+{
+ struct hostlist *hp;
+ struct dirlist *dp2;
+
+ if (alldirs) {
+ if (ep->ex_defdir)
+ free((caddr_t)dp);
+ else
+ ep->ex_defdir = dp;
+ if (grp == (struct grouplist *)NULL)
+ ep->ex_defdir->dp_flag |= DP_DEFSET;
+ else while (grp) {
+ hp = get_ht();
+ hp->ht_grp = grp;
+ hp->ht_next = ep->ex_defdir->dp_hosts;
+ ep->ex_defdir->dp_hosts = hp;
+ grp = grp->gr_next;
+ }
+ } else {
+
+ /*
+ * Loop throught the directories adding them to the tree.
+ */
+ while (dp) {
+ dp2 = dp->dp_left;
+ add_dlist(&ep->ex_dirl, dp, grp);
+ dp = dp2;
+ }
+ }
+}
+
+/*
+ * Traverse the binary tree either updating a node that is already there
+ * for the new directory or adding the new node.
+ */
+void
+add_dlist(dpp, newdp, grp)
+ struct dirlist **dpp;
+ struct dirlist *newdp;
+ struct grouplist *grp;
+{
+ struct dirlist *dp;
+ struct hostlist *hp;
+ int cmp;
+
+ dp = *dpp;
+ if (dp) {
+ cmp = strcmp(dp->dp_dirp, newdp->dp_dirp);
+ if (cmp > 0) {
+ add_dlist(&dp->dp_left, newdp, grp);
+ return;
+ } else if (cmp < 0) {
+ add_dlist(&dp->dp_right, newdp, grp);
+ return;
+ } else
+ free((caddr_t)newdp);
+ } else {
+ dp = newdp;
+ dp->dp_left = (struct dirlist *)NULL;
+ *dpp = dp;
+ }
+ if (grp) {
+
+ /*
+ * Hang all of the host(s) off of the directory point.
+ */
+ do {
+ hp = get_ht();
+ hp->ht_grp = grp;
+ hp->ht_next = dp->dp_hosts;
+ dp->dp_hosts = hp;
+ grp = grp->gr_next;
+ } while (grp);
+ } else
+ dp->dp_flag |= DP_DEFSET;
+}
+
+/*
+ * Search for a dirpath on the export point.
+ */
+struct dirlist *
+dirp_search(dp, dirpath)
+ struct dirlist *dp;
+ char *dirpath;
+{
+ int cmp;
+
+ if (dp) {
+ cmp = strcmp(dp->dp_dirp, dirpath);
+ if (cmp > 0)
+ return (dirp_search(dp->dp_left, dirpath));
+ else if (cmp < 0)
+ return (dirp_search(dp->dp_right, dirpath));
+ else
+ return (dp);
+ }
+ return (dp);
+}
+
+/*
+ * Scan for a host match in a directory tree.
+ */
+int
+chk_host(dp, saddr, defsetp)
+ struct dirlist *dp;
+ u_long saddr;
+ int *defsetp;
+{
+ struct hostlist *hp;
+ struct grouplist *grp;
+ u_long **addrp;
+
+ if (dp) {
+ if (dp->dp_flag & DP_DEFSET)
+ *defsetp = 1;
+ hp = dp->dp_hosts;
+ while (hp) {
+ grp = hp->ht_grp;
+ switch (grp->gr_type) {
+ case GT_HOST:
+ addrp = (u_long **)
+ grp->gr_ptr.gt_hostent->h_addr_list;
+ while (*addrp) {
+ if (**addrp == saddr)
+ return (1);
+ addrp++;
+ }
+ break;
+ case GT_NET:
+ if ((saddr & grp->gr_ptr.gt_net.nt_mask) ==
+ grp->gr_ptr.gt_net.nt_net)
+ return (1);
+ break;
+ };
+ hp = hp->ht_next;
+ }
+ }
+ return (0);
+}
+
+/*
+ * Scan tree for a host that matches the address.
+ */
+int
+scan_tree(dp, saddr)
+ struct dirlist *dp;
+ u_long saddr;
+{
+ int defset;
+
+ if (dp) {
+ if (scan_tree(dp->dp_left, saddr))
+ return (1);
+ if (chk_host(dp, saddr, &defset))
+ return (1);
+ if (scan_tree(dp->dp_right, saddr))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Traverse the dirlist tree and free it up.
+ */
+void
+free_dir(dp)
+ struct dirlist *dp;
+{
+
+ if (dp) {
+ free_dir(dp->dp_left);
+ free_dir(dp->dp_right);
+ free_host(dp->dp_hosts);
+ free((caddr_t)dp);
+ }
+}
+
+/*
+ * Parse the option string and update fields.
+ * Option arguments may either be -<option>=<value> or
+ * -<option> <value>
+ */
+int
+do_opt(cpp, endcpp, ep, grp, has_hostp, exflagsp, cr)
+ char **cpp, **endcpp;
+ struct exportlist *ep;
+ struct grouplist *grp;
+ int *has_hostp;
+ int *exflagsp;
+ struct ucred *cr;
+{
+ char *cpoptarg, *cpoptend;
+ char *cp, *endcp, *cpopt, savedc, savedc2;
+ int allflag, usedarg;
+
+ cpopt = *cpp;
+ cpopt++;
+ cp = *endcpp;
+ savedc = *cp;
+ *cp = '\0';
+ while (cpopt && *cpopt) {
+ allflag = 1;
+ usedarg = -2;
+ if (cpoptend = index(cpopt, ',')) {
+ *cpoptend++ = '\0';
+ if (cpoptarg = index(cpopt, '='))
+ *cpoptarg++ = '\0';
+ } else {
+ if (cpoptarg = index(cpopt, '='))
+ *cpoptarg++ = '\0';
+ else {
+ *cp = savedc;
+ nextfield(&cp, &endcp);
+ **endcpp = '\0';
+ if (endcp > cp && *cp != '-') {
+ cpoptarg = cp;
+ savedc2 = *endcp;
+ *endcp = '\0';
+ usedarg = 0;
+ }
+ }
+ }
+ if (!strcmp(cpopt, "ro") || !strcmp(cpopt, "o")) {
+ *exflagsp |= MNT_EXRDONLY;
+ } else if (cpoptarg && (!strcmp(cpopt, "maproot") ||
+ !(allflag = strcmp(cpopt, "mapall")) ||
+ !strcmp(cpopt, "root") || !strcmp(cpopt, "r"))) {
+ usedarg++;
+ parsecred(cpoptarg, cr);
+ if (allflag == 0) {
+ *exflagsp |= MNT_EXPORTANON;
+ opt_flags |= OP_MAPALL;
+ } else
+ opt_flags |= OP_MAPROOT;
+ } else if (!strcmp(cpopt, "kerb") || !strcmp(cpopt, "k")) {
+ *exflagsp |= MNT_EXKERB;
+ opt_flags |= OP_KERB;
+ } else if (cpoptarg && (!strcmp(cpopt, "mask") ||
+ !strcmp(cpopt, "m"))) {
+ if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 1)) {
+ syslog(LOG_ERR, "Bad mask: %s", cpoptarg);
+ return (1);
+ }
+ usedarg++;
+ opt_flags |= OP_MASK;
+ } else if (cpoptarg && (!strcmp(cpopt, "network") ||
+ !strcmp(cpopt, "n"))) {
+ if (grp->gr_type != GT_NULL) {
+ syslog(LOG_ERR, "Network/host conflict");
+ return (1);
+ } else if (get_net(cpoptarg, &grp->gr_ptr.gt_net, 0)) {
+ syslog(LOG_ERR, "Bad net: %s", cpoptarg);
+ return (1);
+ }
+ grp->gr_type = GT_NET;
+ *has_hostp = 1;
+ usedarg++;
+ opt_flags |= OP_NET;
+ } else if (!strcmp(cpopt, "alldirs")) {
+ opt_flags |= OP_ALLDIRS;
+#ifdef ISO
+ } else if (cpoptarg && !strcmp(cpopt, "iso")) {
+ if (get_isoaddr(cpoptarg, grp)) {
+ syslog(LOG_ERR, "Bad iso addr: %s", cpoptarg);
+ return (1);
+ }
+ *has_hostp = 1;
+ usedarg++;
+ opt_flags |= OP_ISO;
+#endif /* ISO */
+ } else {
+ syslog(LOG_ERR, "Bad opt %s", cpopt);
+ return (1);
+ }
+ if (usedarg >= 0) {
+ *endcp = savedc2;
+ **endcpp = savedc;
+ if (usedarg > 0) {
+ *cpp = cp;
+ *endcpp = endcp;
+ }
+ return (0);
+ }
+ cpopt = cpoptend;
+ }
+ **endcpp = savedc;
+ return (0);
+}
+
+/*
+ * Translate a character string to the corresponding list of network
+ * addresses for a hostname.
+ */
+int
+get_host(cp, grp)
+ char *cp;
+ struct grouplist *grp;
+{
+ struct hostent *hp, *nhp;
+ char **addrp, **naddrp;
+ struct hostent t_host;
+ int i;
+ u_long saddr;
+ char *aptr[2];
+
+ if (grp->gr_type != GT_NULL)
+ return (1);
+ if ((hp = gethostbyname(cp)) == NULL) {
+ if (isdigit(*cp)) {
+ saddr = inet_addr(cp);
+ if (saddr == -1) {
+ syslog(LOG_ERR, "Inet_addr failed");
+ return (1);
+ }
+ if ((hp = gethostbyaddr((caddr_t)&saddr, sizeof (saddr),
+ AF_INET)) == NULL) {
+ hp = &t_host;
+ hp->h_name = cp;
+ hp->h_addrtype = AF_INET;
+ hp->h_length = sizeof (u_long);
+ hp->h_addr_list = aptr;
+ aptr[0] = (char *)&saddr;
+ aptr[1] = (char *)NULL;
+ }
+ } else {
+ syslog(LOG_ERR, "Gethostbyname failed");
+ return (1);
+ }
+ }
+ grp->gr_type = GT_HOST;
+ nhp = grp->gr_ptr.gt_hostent = (struct hostent *)
+ malloc(sizeof(struct hostent));
+ if (nhp == (struct hostent *)NULL)
+ out_of_mem();
+ bcopy((caddr_t)hp, (caddr_t)nhp,
+ sizeof(struct hostent));
+ i = strlen(hp->h_name)+1;
+ nhp->h_name = (char *)malloc(i);
+ if (nhp->h_name == (char *)NULL)
+ out_of_mem();
+ bcopy(hp->h_name, nhp->h_name, i);
+ addrp = hp->h_addr_list;
+ i = 1;
+ while (*addrp++)
+ i++;
+ naddrp = nhp->h_addr_list = (char **)
+ malloc(i*sizeof(char *));
+ if (naddrp == (char **)NULL)
+ out_of_mem();
+ addrp = hp->h_addr_list;
+ while (*addrp) {
+ *naddrp = (char *)
+ malloc(hp->h_length);
+ if (*naddrp == (char *)NULL)
+ out_of_mem();
+ bcopy(*addrp, *naddrp,
+ hp->h_length);
+ addrp++;
+ naddrp++;
+ }
+ *naddrp = (char *)NULL;
+ if (debug)
+ fprintf(stderr, "got host %s\n", hp->h_name);
+ return (0);
+}
+
+/*
+ * Free up an exports list component
+ */
+void
+free_exp(ep)
+ struct exportlist *ep;
+{
+
+ if (ep->ex_defdir) {
+ free_host(ep->ex_defdir->dp_hosts);
+ free((caddr_t)ep->ex_defdir);
+ }
+ if (ep->ex_fsdir)
+ free(ep->ex_fsdir);
+ free_dir(ep->ex_dirl);
+ free((caddr_t)ep);
+}
+
+/*
+ * Free hosts.
+ */
+void
+free_host(hp)
+ struct hostlist *hp;
+{
+ struct hostlist *hp2;
+
+ while (hp) {
+ hp2 = hp;
+ hp = hp->ht_next;
+ free((caddr_t)hp2);
+ }
+}
+
+struct hostlist *
+get_ht()
+{
+ struct hostlist *hp;
+
+ hp = (struct hostlist *)malloc(sizeof (struct hostlist));
+ if (hp == (struct hostlist *)NULL)
+ out_of_mem();
+ hp->ht_next = (struct hostlist *)NULL;
+ return (hp);
+}
+
+#ifdef ISO
+/*
+ * Translate an iso address.
+ */
+get_isoaddr(cp, grp)
+ char *cp;
+ struct grouplist *grp;
+{
+ struct iso_addr *isop;
+ struct sockaddr_iso *isoaddr;
+
+ if (grp->gr_type != GT_NULL)
+ return (1);
+ if ((isop = iso_addr(cp)) == NULL) {
+ syslog(LOG_ERR,
+ "iso_addr failed, ignored");
+ return (1);
+ }
+ isoaddr = (struct sockaddr_iso *)
+ malloc(sizeof (struct sockaddr_iso));
+ if (isoaddr == (struct sockaddr_iso *)NULL)
+ out_of_mem();
+ bzero((caddr_t)isoaddr, sizeof (struct sockaddr_iso));
+ bcopy((caddr_t)isop, (caddr_t)&isoaddr->siso_addr,
+ sizeof (struct iso_addr));
+ isoaddr->siso_len = sizeof (struct sockaddr_iso);
+ isoaddr->siso_family = AF_ISO;
+ grp->gr_type = GT_ISO;
+ grp->gr_ptr.gt_isoaddr = isoaddr;
+ return (0);
+}
+#endif /* ISO */
+
+/*
+ * Out of memory, fatal
+ */
+void
+out_of_mem()
+{
+
+ syslog(LOG_ERR, "Out of memory");
+ exit(2);
+}
+
+/*
+ * Do the mount syscall with the update flag to push the export info into
+ * the kernel.
+ */
+int
+do_mount(ep, grp, exflags, anoncrp, dirp, dirplen, fsb)
+ struct exportlist *ep;
+ struct grouplist *grp;
+ int exflags;
+ struct ucred *anoncrp;
+ char *dirp;
+ int dirplen;
+ struct statfs *fsb;
+{
+ char *cp = (char *)NULL;
+ u_long **addrp;
+ int done;
+ char savedc = '\0';
+ struct sockaddr_in sin, imask;
+ union {
+ struct ufs_args ua;
+ struct iso_args ia;
+ struct mfs_args ma;
+ } args;
+ u_long net;
+
+ args.ua.fspec = 0;
+ args.ua.export.ex_flags = exflags;
+ args.ua.export.ex_anon = *anoncrp;
+ bzero((char *)&sin, sizeof(sin));
+ bzero((char *)&imask, sizeof(imask));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(sin);
+ imask.sin_family = AF_INET;
+ imask.sin_len = sizeof(sin);
+ if (grp->gr_type == GT_HOST)
+ addrp = (u_long **)grp->gr_ptr.gt_hostent->h_addr_list;
+ else
+ addrp = (u_long **)NULL;
+ done = FALSE;
+ while (!done) {
+ switch (grp->gr_type) {
+ case GT_HOST:
+ if (addrp) {
+ sin.sin_addr.s_addr = **addrp;
+ args.ua.export.ex_addrlen = sizeof(sin);
+ } else
+ args.ua.export.ex_addrlen = 0;
+ args.ua.export.ex_addr = (struct sockaddr *)&sin;
+ args.ua.export.ex_masklen = 0;
+ break;
+ case GT_NET:
+ if (grp->gr_ptr.gt_net.nt_mask)
+ imask.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_mask;
+ else {
+ net = ntohl(grp->gr_ptr.gt_net.nt_net);
+ if (IN_CLASSA(net))
+ imask.sin_addr.s_addr = inet_addr("255.0.0.0");
+ else if (IN_CLASSB(net))
+ imask.sin_addr.s_addr =
+ inet_addr("255.255.0.0");
+ else
+ imask.sin_addr.s_addr =
+ inet_addr("255.255.255.0");
+ grp->gr_ptr.gt_net.nt_mask = imask.sin_addr.s_addr;
+ }
+ sin.sin_addr.s_addr = grp->gr_ptr.gt_net.nt_net;
+ args.ua.export.ex_addr = (struct sockaddr *)&sin;
+ args.ua.export.ex_addrlen = sizeof (sin);
+ args.ua.export.ex_mask = (struct sockaddr *)&imask;
+ args.ua.export.ex_masklen = sizeof (imask);
+ break;
+#ifdef ISO
+ case GT_ISO:
+ args.ua.export.ex_addr =
+ (struct sockaddr *)grp->gr_ptr.gt_isoaddr;
+ args.ua.export.ex_addrlen =
+ sizeof(struct sockaddr_iso);
+ args.ua.export.ex_masklen = 0;
+ break;
+#endif /* ISO */
+ default:
+ syslog(LOG_ERR, "Bad grouptype");
+ if (cp)
+ *cp = savedc;
+ return (1);
+ };
+
+ /*
+ * XXX:
+ * Maybe I should just use the fsb->f_mntonname path instead
+ * of looping back up the dirp to the mount point??
+ * Also, needs to know how to export all types of local
+ * exportable file systems and not just MOUNT_UFS.
+ */
+ while (mount(fsb->f_type, dirp,
+ fsb->f_flags | MNT_UPDATE, (caddr_t)&args) < 0) {
+ if (cp)
+ *cp-- = savedc;
+ else
+ cp = dirp + dirplen - 1;
+ if (errno == EPERM) {
+ syslog(LOG_ERR,
+ "Can't change attributes for %s.\n", dirp);
+ return (1);
+ }
+ if (opt_flags & OP_ALLDIRS) {
+ syslog(LOG_ERR, "Not root dir");
+ return (1);
+ }
+ /* back up over the last component */
+ while (*cp == '/' && cp > dirp)
+ cp--;
+ while (*(cp - 1) != '/' && cp > dirp)
+ cp--;
+ if (cp == dirp) {
+ if (debug)
+ fprintf(stderr,"mnt unsucc\n");
+ syslog(LOG_ERR, "Can't export %s", dirp);
+ return (1);
+ }
+ savedc = *cp;
+ *cp = '\0';
+ }
+ if (addrp) {
+ ++addrp;
+ if (*addrp == (u_long *)NULL)
+ done = TRUE;
+ } else
+ done = TRUE;
+ }
+ if (cp)
+ *cp = savedc;
+ return (0);
+}
+
+/*
+ * Translate a net address.
+ */
+int
+get_net(cp, net, maskflg)
+ char *cp;
+ struct netmsk *net;
+ int maskflg;
+{
+ struct netent *np;
+ long netaddr;
+ struct in_addr inetaddr, inetaddr2;
+ char *name;
+
+ if (np = getnetbyname(cp))
+ inetaddr = inet_makeaddr(np->n_net, 0);
+ else if (isdigit(*cp)) {
+ if ((netaddr = inet_network(cp)) == -1)
+ return (1);
+ inetaddr = inet_makeaddr(netaddr, 0);
+ /*
+ * Due to arbritrary subnet masks, you don't know how many
+ * bits to shift the address to make it into a network,
+ * however you do know how to make a network address into
+ * a host with host == 0 and then compare them.
+ * (What a pest)
+ */
+ if (!maskflg) {
+ setnetent(0);
+ while (np = getnetent()) {
+ inetaddr2 = inet_makeaddr(np->n_net, 0);
+ if (inetaddr2.s_addr == inetaddr.s_addr)
+ break;
+ }
+ endnetent();
+ }
+ } else
+ return (1);
+ if (maskflg)
+ net->nt_mask = inetaddr.s_addr;
+ else {
+ if (np)
+ name = np->n_name;
+ else
+ name = inet_ntoa(inetaddr);
+ net->nt_name = (char *)malloc(strlen(name) + 1);
+ if (net->nt_name == (char *)NULL)
+ out_of_mem();
+ strcpy(net->nt_name, name);
+ net->nt_net = inetaddr.s_addr;
+ }
+ return (0);
+}
+
+/*
+ * Parse out the next white space separated field
+ */
+void
+nextfield(cp, endcp)
+ char **cp;
+ char **endcp;
+{
+ char *p;
+
+ p = *cp;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '\n' || *p == '\0')
+ *cp = *endcp = p;
+ else {
+ *cp = p++;
+ while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0')
+ p++;
+ *endcp = p;
+ }
+}
+
+/*
+ * Get an exports file line. Skip over blank lines and handle line
+ * continuations.
+ */
+int
+get_line()
+{
+ char *p, *cp;
+ int len;
+ int totlen, cont_line;
+
+ /*
+ * Loop around ignoring blank lines and getting all continuation lines.
+ */
+ p = line;
+ totlen = 0;
+ do {
+ if (fgets(p, LINESIZ - totlen, exp_file) == NULL)
+ return (0);
+ len = strlen(p);
+ cp = p + len - 1;
+ cont_line = 0;
+ while (cp >= p &&
+ (*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '\\')) {
+ if (*cp == '\\')
+ cont_line = 1;
+ cp--;
+ len--;
+ }
+ *++cp = '\0';
+ if (len > 0) {
+ totlen += len;
+ if (totlen >= LINESIZ) {
+ syslog(LOG_ERR, "Exports line too long");
+ exit(2);
+ }
+ p = cp;
+ }
+ } while (totlen == 0 || cont_line);
+ return (1);
+}
+
+/*
+ * Parse a description of a credential.
+ */
+void
+parsecred(namelist, cr)
+ char *namelist;
+ struct ucred *cr;
+{
+ char *name;
+ int cnt;
+ char *names;
+ struct passwd *pw;
+ struct group *gr;
+ int ngroups, groups[NGROUPS + 1];
+
+ /*
+ * Set up the unpriviledged user.
+ */
+ cr->cr_ref = 1;
+ cr->cr_uid = -2;
+ cr->cr_groups[0] = -2;
+ cr->cr_ngroups = 1;
+ /*
+ * Get the user's password table entry.
+ */
+ names = strsep(&namelist, " \t\n");
+ name = strsep(&names, ":");
+ if (isdigit(*name) || *name == '-')
+ pw = getpwuid(atoi(name));
+ else
+ pw = getpwnam(name);
+ /*
+ * Credentials specified as those of a user.
+ */
+ if (names == NULL) {
+ if (pw == NULL) {
+ syslog(LOG_ERR, "Unknown user: %s", name);
+ return;
+ }
+ cr->cr_uid = pw->pw_uid;
+ ngroups = NGROUPS + 1;
+ if (getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups))
+ syslog(LOG_ERR, "Too many groups");
+ /*
+ * Convert from int's to gid_t's and compress out duplicate
+ */
+ cr->cr_ngroups = ngroups - 1;
+ cr->cr_groups[0] = groups[0];
+ for (cnt = 2; cnt < ngroups; cnt++)
+ cr->cr_groups[cnt - 1] = groups[cnt];
+ return;
+ }
+ /*
+ * Explicit credential specified as a colon separated list:
+ * uid:gid:gid:...
+ */
+ if (pw != NULL)
+ cr->cr_uid = pw->pw_uid;
+ else if (isdigit(*name) || *name == '-')
+ cr->cr_uid = atoi(name);
+ else {
+ syslog(LOG_ERR, "Unknown user: %s", name);
+ return;
+ }
+ cr->cr_ngroups = 0;
+ while (names != NULL && *names != '\0' && cr->cr_ngroups < NGROUPS) {
+ name = strsep(&names, ":");
+ if (isdigit(*name) || *name == '-') {
+ cr->cr_groups[cr->cr_ngroups++] = atoi(name);
+ } else {
+ if ((gr = getgrnam(name)) == NULL) {
+ syslog(LOG_ERR, "Unknown group: %s", name);
+ continue;
+ }
+ cr->cr_groups[cr->cr_ngroups++] = gr->gr_gid;
+ }
+ }
+ if (names != NULL && *names != '\0' && cr->cr_ngroups == NGROUPS)
+ syslog(LOG_ERR, "Too many groups");
+}
+
+#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+50)
+/*
+ * Routines that maintain the remote mounttab
+ */
+void
+get_mountlist()
+{
+ struct mountlist *mlp, **mlpp;
+ char *eos, *dirp;
+ int len;
+ char str[STRSIZ];
+ FILE *mlfile;
+
+ if ((mlfile = fopen(_PATH_RMOUNTLIST, "r")) == NULL) {
+ syslog(LOG_ERR, "Can't open %s", _PATH_RMOUNTLIST);
+ return;
+ }
+ mlpp = &mlhead;
+ while (fgets(str, STRSIZ, mlfile) != NULL) {
+ if ((dirp = index(str, '\t')) == NULL &&
+ (dirp = index(str, ' ')) == NULL)
+ continue;
+ mlp = (struct mountlist *)malloc(sizeof (*mlp));
+ len = dirp-str;
+ if (len > RPCMNT_NAMELEN)
+ len = RPCMNT_NAMELEN;
+ bcopy(str, mlp->ml_host, len);
+ mlp->ml_host[len] = '\0';
+ while (*dirp == '\t' || *dirp == ' ')
+ dirp++;
+ if ((eos = index(dirp, '\t')) == NULL &&
+ (eos = index(dirp, ' ')) == NULL &&
+ (eos = index(dirp, '\n')) == NULL)
+ len = strlen(dirp);
+ else
+ len = eos-dirp;
+ if (len > RPCMNT_PATHLEN)
+ len = RPCMNT_PATHLEN;
+ bcopy(dirp, mlp->ml_dirp, len);
+ mlp->ml_dirp[len] = '\0';
+ mlp->ml_next = (struct mountlist *)NULL;
+ *mlpp = mlp;
+ mlpp = &mlp->ml_next;
+ }
+ fclose(mlfile);
+}
+
+void
+del_mlist(hostp, dirp)
+ char *hostp, *dirp;
+{
+ struct mountlist *mlp, **mlpp;
+ struct mountlist *mlp2;
+ FILE *mlfile;
+ int fnd = 0;
+
+ mlpp = &mlhead;
+ mlp = mlhead;
+ while (mlp) {
+ if (!strcmp(mlp->ml_host, hostp) &&
+ (!dirp || !strcmp(mlp->ml_dirp, dirp))) {
+ fnd = 1;
+ mlp2 = mlp;
+ *mlpp = mlp = mlp->ml_next;
+ free((caddr_t)mlp2);
+ } else {
+ mlpp = &mlp->ml_next;
+ mlp = mlp->ml_next;
+ }
+ }
+ if (fnd) {
+ if ((mlfile = fopen(_PATH_RMOUNTLIST, "w")) == NULL) {
+ syslog(LOG_ERR,"Can't update %s", _PATH_RMOUNTLIST);
+ return;
+ }
+ mlp = mlhead;
+ while (mlp) {
+ fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
+ mlp = mlp->ml_next;
+ }
+ fclose(mlfile);
+ }
+}
+
+void
+add_mlist(hostp, dirp)
+ char *hostp, *dirp;
+{
+ struct mountlist *mlp, **mlpp;
+ FILE *mlfile;
+
+ mlpp = &mlhead;
+ mlp = mlhead;
+ while (mlp) {
+ if (!strcmp(mlp->ml_host, hostp) && !strcmp(mlp->ml_dirp, dirp))
+ return;
+ mlpp = &mlp->ml_next;
+ mlp = mlp->ml_next;
+ }
+ mlp = (struct mountlist *)malloc(sizeof (*mlp));
+ strncpy(mlp->ml_host, hostp, RPCMNT_NAMELEN);
+ mlp->ml_host[RPCMNT_NAMELEN] = '\0';
+ strncpy(mlp->ml_dirp, dirp, RPCMNT_PATHLEN);
+ mlp->ml_dirp[RPCMNT_PATHLEN] = '\0';
+ mlp->ml_next = (struct mountlist *)NULL;
+ *mlpp = mlp;
+ if ((mlfile = fopen(_PATH_RMOUNTLIST, "a")) == NULL) {
+ syslog(LOG_ERR, "Can't update %s", _PATH_RMOUNTLIST);
+ return;
+ }
+ fprintf(mlfile, "%s %s\n", mlp->ml_host, mlp->ml_dirp);
+ fclose(mlfile);
+}
+
+/*
+ * This function is called via. SIGTERM when the system is going down.
+ * It sends a broadcast RPCMNT_UMNTALL.
+ */
+void
+send_umntall()
+{
+ (void) clnt_broadcast(RPCPROG_MNT, RPCMNT_VER1, RPCMNT_UMNTALL,
+ xdr_void, (caddr_t)0, xdr_void, (caddr_t)0, umntall_each);
+ exit(0);
+}
+
+int
+umntall_each(resultsp, raddr)
+ caddr_t resultsp;
+ struct sockaddr_in *raddr;
+{
+ return (1);
+}
+
+/*
+ * Free up a group list.
+ */
+void
+free_grp(grp)
+ struct grouplist *grp;
+{
+ char **addrp;
+
+ if (grp->gr_type == GT_HOST) {
+ if (grp->gr_ptr.gt_hostent->h_name) {
+ addrp = grp->gr_ptr.gt_hostent->h_addr_list;
+ while (addrp && *addrp)
+ free(*addrp++);
+ free((caddr_t)grp->gr_ptr.gt_hostent->h_addr_list);
+ free(grp->gr_ptr.gt_hostent->h_name);
+ }
+ free((caddr_t)grp->gr_ptr.gt_hostent);
+ } else if (grp->gr_type == GT_NET) {
+ if (grp->gr_ptr.gt_net.nt_name)
+ free(grp->gr_ptr.gt_net.nt_name);
+ }
+#ifdef ISO
+ else if (grp->gr_type == GT_ISO)
+ free((caddr_t)grp->gr_ptr.gt_isoaddr);
+#endif
+ free((caddr_t)grp);
+}
+
+#ifdef DEBUG
+void
+SYSLOG(int pri, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+#endif /* DEBUG */
+
+/*
+ * Check options for consistency.
+ */
+int
+check_options(dp)
+ struct dirlist *dp;
+{
+
+ if (dp == (struct dirlist *)NULL)
+ return (1);
+ if ((opt_flags & (OP_MAPROOT | OP_MAPALL)) == (OP_MAPROOT | OP_MAPALL) ||
+ (opt_flags & (OP_MAPROOT | OP_KERB)) == (OP_MAPROOT | OP_KERB) ||
+ (opt_flags & (OP_MAPALL | OP_KERB)) == (OP_MAPALL | OP_KERB)) {
+ syslog(LOG_ERR, "-mapall, -maproot and -kerb mutually exclusive");
+ return (1);
+ }
+ if ((opt_flags & OP_MASK) && (opt_flags & OP_NET) == 0) {
+ syslog(LOG_ERR, "-mask requires -net");
+ return (1);
+ }
+ if ((opt_flags & (OP_NET | OP_ISO)) == (OP_NET | OP_ISO)) {
+ syslog(LOG_ERR, "-net and -iso mutually exclusive");
+ return (1);
+ }
+ if ((opt_flags & OP_ALLDIRS) && dp->dp_left) {
+ syslog(LOG_ERR, "-alldir has multiple directories");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Check an absolute directory path for any symbolic links. Return true
+ * if no symbolic links are found.
+ */
+int
+check_dirpath(dirp)
+ char *dirp;
+{
+ char *cp;
+ int ret = 1;
+ struct stat sb;
+
+ cp = dirp + 1;
+ while (*cp && ret) {
+ if (*cp == '/') {
+ *cp = '\0';
+ if (lstat(dirp, &sb) < 0 ||
+ (sb.st_mode & S_IFMT) != S_IFDIR)
+ ret = 0;
+ *cp = '/';
+ }
+ cp++;
+ }
+ if (lstat(dirp, &sb) < 0 ||
+ (sb.st_mode & S_IFMT) != S_IFDIR)
+ ret = 0;
+ return (ret);
+}
diff --git a/usr.sbin/mountd/netgroup.5 b/usr.sbin/mountd/netgroup.5
new file mode 100644
index 0000000..9ad8c48
--- /dev/null
+++ b/usr.sbin/mountd/netgroup.5
@@ -0,0 +1,91 @@
+.\" 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.
+.\"
+.\" @(#)netgroup.5 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt NETGROUP 5
+.Os
+.Sh NAME
+.Nm netgroup
+.Nd defines network groups
+.Sh SYNOPSIS
+.Nm netgroup
+.Sh DESCRIPTION
+The
+.Nm netgroup
+file
+specifies ``netgroups'', which are sets of
+.Sy (host, user, domain)
+tuples that are to be given similar network access.
+.Pp
+Each line in the file
+consists of a netgroup name followed by a list of the members of the
+netgroup.
+Each member can be either the name of another netgroup or a specification
+of a tuple as follows:
+.Bd -literal -offset indent
+(host, user, domain)
+.Ed
+where the
+.Sy host ,
+.Sy user ,
+and
+.Sy domain
+are character string names for the corresponding component.
+Any of the comma separated fields may be empty to specify a ``wildcard'' value
+or may consist of the string ``-'' to specify ``no valid value''.
+The members of the list may be separated by whitespace and/or commas;
+the ``\e'' character may be used at the end of a line to specify
+line continuation.
+The functions specified in
+.Xr getnetgrent 3
+should normally be used to access the
+.Nm netgroup
+database.
+.Pp
+Lines that begin with a # are treated as comments.
+.Sh FILES
+.Bl -tag -width /etc/netgroup -compact
+.It Pa /etc/netgroup
+the netgroup database.
+.El
+.Sh SEE ALSO
+.Xr getnetgrent 3 ,
+.Xr exports 5
+.Sh COMPATIBILITY
+The file format is compatible with that of various vendors, however it
+appears that not all vendors use an identical format.
+.Sh BUGS
+The interpretation of access restrictions based on the member tuples of a
+netgroup is left up to the various network applications.
+Also, it is not obvious how the domain specification
+applies to the BSD environment.
diff --git a/usr.sbin/mountd/pathnames.h b/usr.sbin/mountd/pathnames.h
new file mode 100644
index 0000000..aa1c555
--- /dev/null
+++ b/usr.sbin/mountd/pathnames.h
@@ -0,0 +1,39 @@
+/*
+ * 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/5/93
+ */
+#include <paths.h>
+
+#define _PATH_EXPORTS "/etc/exports"
+#define _PATH_RMOUNTLIST "/var/db/mountdtab"
+#define _PATH_MOUNTDPID "/var/run/mountd.pid"
diff --git a/usr.sbin/mrouted/LICENSE b/usr.sbin/mrouted/LICENSE
new file mode 100644
index 0000000..ef7da47
--- /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 0000000..c77b1fb
--- /dev/null
+++ b/usr.sbin/mrouted/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+
+SUBDIR= common mrouted mrinfo map-mbone mtrace
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/mrouted/Makefile.inc b/usr.sbin/mrouted/Makefile.inc
new file mode 100644
index 0000000..8137233
--- /dev/null
+++ b/usr.sbin/mrouted/Makefile.inc
@@ -0,0 +1 @@
+.include "${.CURDIR}/../../Makefile.inc"
diff --git a/usr.sbin/mrouted/callout.c b/usr.sbin/mrouted/callout.c
new file mode 100644
index 0000000..0538a3f
--- /dev/null
+++ b/usr.sbin/mrouted/callout.c
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: callout.c,v 1.1 1994/08/24 23:52:49 thyagara Exp $
+ */
+
+#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*/
+};
+
+
+callout_init()
+{
+ Q = (struct timeout_q *) 0;
+}
+
+
+/*
+ * signal handler for SIGALARM that is called once every second
+ */
+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;
+
+ in_callout = 1;
+
+ /* create a node */
+ node = (struct timeout_q *)malloc(sizeof(struct timeout_q));
+ if ((int) 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( id)
+ int id;
+{
+ struct timeout_q *ptr, *prev;
+
+ if (in_callout) return;
+ in_callout = 1;
+
+
+ if ( !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 == 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
+ */
+print_Q()
+{
+ struct timeout_q *ptr;
+
+#ifdef IGMP_DEBUG
+ 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/common/Makefile b/usr.sbin/mrouted/common/Makefile
new file mode 100644
index 0000000..9bcfb27
--- /dev/null
+++ b/usr.sbin/mrouted/common/Makefile
@@ -0,0 +1,17 @@
+# $Id$
+
+LIB= mrouted
+NOPROFILE=
+NOSHARED=
+
+S= ${.CURDIR}/..
+.PATH: $S
+CFLAGS+= -I$S
+
+SRCS= igmp.c inet.c kern.c
+NOMAN=
+
+# nothing to install
+install:
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/mrouted/config.c b/usr.sbin/mrouted/config.c
new file mode 100644
index 0000000..c7aa7b0
--- /dev/null
+++ b/usr.sbin/mrouted/config.c
@@ -0,0 +1,796 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: config.c,v 1.6 1994/08/24 23:52:54 thyagara Exp $
+ */
+
+
+#include "defs.h"
+
+
+char *configfilename = "/etc/mrouted.conf";
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+/*
+ * Forward declarations.
+ */
+static char *next_word();
+
+
+/*
+ * 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, *mp;
+ struct ifconf ifc;
+ register struct uvif *v;
+ register vifi_t vifi;
+ int i, n;
+ u_long 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.
+ */
+ addr = ((struct sockaddr_in *)&ifrp->ifr_addr)->sin_addr.s_addr;
+ if (ifrp->ifr_addr.sa_family != AF_INET)
+ continue;
+
+ /*
+ * 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 (%08x)",
+ ifr.ifr_name, inet_fmt(addr, s1), ntohl(mask));
+ 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_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;
+
+ 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;
+ }
+ }
+}
+
+static struct ifreq *
+ifconfaddr(ifcp, a)
+ struct ifconf *ifcp;
+ u_long 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 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);
+}
+
+/*
+ * Checks if the string constitutes a valid interface name
+ */
+static u_long valid_if(w)
+char *w;
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++)
+ if (EQUAL(v->uv_name, w))
+ return v->uv_lcl_addr;
+
+ return NULL;
+}
+
+/*
+ * Read the config file to learn about tunnel vifs and
+ * non-default phyint parameters.
+ */
+void config_vifs_from_file()
+{
+ FILE *f;
+ char linebuf[100];
+ char *w, *s, c;
+ u_long lcl_addr, rmt_addr;
+ struct ifconf ifc;
+ struct ifreq *ifr;
+ struct ifreq ffr;
+ int i;
+ u_int n;
+ struct ifreq ifbuf[32];
+ vifi_t vifi;
+ struct uvif *v;
+ u_char order = 0;
+ vifi_t prev_vif = NO_VIF;
+
+ f = fopen(configfilename, "r");
+ if (f == 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");
+
+ while (fgets(linebuf, sizeof(linebuf), f) != NULL) {
+
+ s = linebuf;
+ if (EQUAL((w = next_word(&s)), "")) {
+ /*
+ * blank or comment line; ignore
+ */
+ }
+
+ /* Set the cache_lifetime for kernel entries */
+ else if (EQUAL(w, "cache_lifetime")) {
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing cache_lifetime value in %s",
+ configfilename);
+ continue;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 300 || n > 86400 ) {
+ log(LOG_ERR, 0,
+ "invalid cache_lifetime '%s' (300<n>86400) in %s",
+ w, configfilename);
+ break;
+ }
+ prev_vif = NO_VIF;
+ cache_lifetime = n;
+ max_prune_lifetime = cache_lifetime * 2;
+ }
+
+ /* Check if pruning is to be turned off */
+ else if (EQUAL(w, "pruning")) {
+ if (!EQUAL((w = next_word(&s)), "off") &&
+ !EQUAL(w, "on")) {
+ log(LOG_ERR, 0,
+ "invalid word '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+ if (EQUAL(w, "off"))
+ pruning = 0;
+
+ prev_vif = NO_VIF;
+ }
+
+ /* Check for boundary statements (as continuation of a prev. line) */
+ else if (EQUAL(w, "boundary") && prev_vif != NO_VIF) {
+ register struct vif_acl *v_acl;
+ register u_long baddr;
+
+ v = &uvifs[prev_vif];
+
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing group address for boundary %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+
+ if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
+ n < 0 || n> 32) {
+ log(LOG_ERR, 0,
+ "incorrect boundary format %s in %s",
+ w, configfilename);
+ w = "garbage";
+ break;
+ }
+
+ if ((baddr = inet_parse(s1)) == 0xffffffff ||
+ (baddr & 0xff000000) != 0xef000000) {
+ log(LOG_ERR, 0,
+ "incorrect boundary address %s in %s",
+ s1, configfilename);
+ continue;
+ }
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ log(LOG_ERR, 0,
+ "out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, n);
+ v_acl->acl_addr = baddr & v_acl->acl_mask;
+
+ /*
+ * link into data structure
+ */
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+ }
+
+ else if (EQUAL(w, "phyint")) {
+ /*
+ * phyint <local-addr> [disable] [metric <m>] [threshold <t>]
+ * [rate_limit <b>]
+ */
+
+ /*
+ * Check if phyint was the first line - scream if not
+ */
+ if (order) {
+ log(LOG_ERR, 0,
+ "phyint stmnts should occur before tunnel stmnts in %s",
+ configfilename);
+ continue;
+ }
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing phyint address in %s",
+ configfilename);
+ continue;
+ }
+
+ if (isalpha(*w) && !(lcl_addr = valid_if(w))) {
+ log(LOG_ERR, 0,
+ "invalid phyint name '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ if (isdigit(*w)) {
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_ERR, 0,
+ "invalid phyint address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+ }
+
+ /*
+ * Look up the vif with the specified local address.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ lcl_addr == v->uv_lcl_addr) {
+ break;
+ }
+ }
+
+ if (vifi == numvifs) {
+ log(LOG_ERR, 0,
+ "phyint %s in %s is not a configured interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Look for "disable", "metric", "threshold", "rate_limit"
+ * and "boundary" options.
+ */
+ prev_vif = vifi;
+
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "disable")) {
+ v->uv_flags |= VIFF_DISABLED;
+ }
+ else if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing metric for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_ERR, 0,
+ "invalid metric '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing threshold for phyint %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_ERR, 0,
+ "invalid threshold '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else if (EQUAL(w, "rate_limit")) {
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing rate_limit for phyint %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 0 || n > MAX_RATE_LIMIT ) {
+ log(LOG_ERR, 0,
+ "invalid rate limit '%s' for phyint %s in %s",
+ w, inet_fmt(lcl_addr, s1), configfilename);
+ break;
+ }
+ v->uv_rate_limit = n;
+ }
+ else if (EQUAL(w, "boundary")) {
+ register struct vif_acl *v_acl;
+ register u_long baddr;
+
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing group address for boundary %s in %s",
+ inet_fmt(lcl_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+
+ if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
+ n < 0 || n> 32) {
+ log(LOG_ERR, 0,
+ "incorrect boundary format %s in %s",
+ w, configfilename);
+ w = "garbage";
+ break;
+ }
+
+ if ((baddr = inet_parse(s1)) == 0xffffffff ||
+ (baddr & 0xef000000) != 0xef000000) {
+ log(LOG_ERR, 0,
+ "incorrect boundary address %s in %s",
+ s1, configfilename);
+ continue;
+ }
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ log(LOG_ERR, 0,
+ "out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, n);
+ v_acl->acl_addr = baddr & v_acl->acl_mask;
+
+ /*
+ * link into data structure
+ */
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+ }
+ else {
+ log(LOG_ERR, 0,
+ "invalid keyword (%s) in %s",
+ w, configfilename);
+ break;
+ }
+ }
+ if (!EQUAL(w, "")) continue;
+ }
+
+ else if (EQUAL(w, "tunnel")) {
+ /*
+ * tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
+ * [threshold <t>] [rate_limit <b>]
+ */
+
+ order++;
+
+ /*
+ * Parse the local address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing tunnel local address in %s",
+ configfilename);
+ continue;
+ }
+ if ((lcl_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(lcl_addr)) {
+ log(LOG_ERR, 0,
+ "invalid tunnel local address '%s' in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address is one of ours.
+ */
+ ifr = ifconfaddr(&ifc, lcl_addr);
+ if (ifr == 0) {
+ log(LOG_ERR, 0,
+ "tunnel local address %s in %s is not one of ours",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the local address doesn't name a loopback interface..
+ */
+ strncpy(ffr.ifr_name, ifr->ifr_name, IFNAMSIZ);
+ if (ioctl(udp_socket, SIOCGIFFLAGS, (char *)&ffr) < 0) {
+ log(LOG_ERR, errno,
+ "ioctl SIOCGIFFLAGS for %s", ffr.ifr_name);
+ }
+ if (ffr.ifr_flags & IFF_LOOPBACK) {
+ log(LOG_ERR, 0,
+ "tunnel local address %s in %s is a loopback interface",
+ inet_fmt(lcl_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Parse the remote address.
+ */
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing tunnel remote address in %s",
+ configfilename);
+ continue;
+ }
+ if ((rmt_addr = inet_parse(w)) == 0xffffffff ||
+ !inet_valid_host(rmt_addr)) {
+ log(LOG_ERR, 0,
+ "invalid tunnel remote address %s in %s",
+ w, configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address is not one of ours.
+ */
+ if (ifconfaddr(&ifc, rmt_addr) != 0) {
+ log(LOG_ERR, 0,
+ "tunnel remote address %s in %s is one of ours",
+ inet_fmt(rmt_addr, s1), configfilename);
+ continue;
+ }
+
+ /*
+ * Make sure the remote address has not been used for another
+ * tunnel and does not belong to a subnet to which we have direct
+ * access on an enabled phyint.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (v->uv_flags & VIFF_TUNNEL) {
+ if (rmt_addr == v->uv_rmt_addr) {
+ log(LOG_ERR, 0,
+ "duplicate tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ else if (!(v->uv_flags & VIFF_DISABLED)) {
+ if ((rmt_addr & v->uv_subnetmask) == v->uv_subnet) {
+ log(LOG_ERR, 0,
+ "unnecessary tunnel remote address %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ }
+ }
+ if (vifi != numvifs) continue;
+
+ /*
+ * OK, let's initialize a uvif structure for the tunnel.
+ */
+ if (numvifs == MAXVIFS) {
+ log(LOG_ERR, 0, "too many vifs, ignoring tunnel to %s",
+ inet_fmt(rmt_addr, s1));
+ continue;
+ }
+ v = &uvifs[numvifs];
+ v->uv_flags = VIFF_TUNNEL;
+ v->uv_metric = DEFAULT_METRIC;
+ v->uv_rate_limit = DEFAULT_RATE_LIMIT;
+ v->uv_threshold = DEFAULT_THRESHOLD;
+ v->uv_lcl_addr = lcl_addr;
+ v->uv_rmt_addr = rmt_addr;
+ 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;
+
+ /*
+ * set variable to define which interface
+ */
+ prev_vif = numvifs;
+
+ /*
+ * Look for "metric", "threshold", "srcrt", "rate_limit"
+ * and "boundary" options.
+ */
+ while (!EQUAL((w = next_word(&s)), "")) {
+ if (EQUAL(w, "metric")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing metric for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n >= UNREACHABLE ) {
+ log(LOG_ERR, 0,
+ "invalid metric '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_metric = n;
+ }
+ else if (EQUAL(w, "threshold")) {
+ if(EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing threshold for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 1 || n > 255 ) {
+ log(LOG_ERR, 0,
+ "invalid threshold '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_threshold = n;
+ }
+ else if (EQUAL(w, "srcrt") || EQUAL(w, "sourceroute")) {
+ v->uv_flags |= VIFF_SRCRT;
+ }
+ else if (EQUAL(w, "rate_limit")) {
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing rate_limit for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+ if(sscanf(w, "%u%c", &n, &c) != 1 ||
+ n < 0 || n > MAX_RATE_LIMIT ) {
+ log(LOG_ERR, 0,
+ "invalid rate_limit '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+ v->uv_rate_limit = n;
+ }
+ else if (EQUAL(w, "boundary")) {
+ register struct vif_acl *v_acl;
+ register u_long baddr;
+
+ if (EQUAL((w = next_word(&s)), "")) {
+ log(LOG_ERR, 0,
+ "missing group address for tunnel to %s in %s",
+ inet_fmt(rmt_addr, s1), configfilename);
+ w = "garbage";
+ break;
+ }
+
+ if ((sscanf(w, "%[0-9.]/%d", s1, &n) != 2) ||
+ n < 0 || n> 32) {
+ log(LOG_ERR, 0,
+ "incorrect format '%s' for tunnel to %s in %s",
+ w, inet_fmt(rmt_addr, s1), configfilename);
+ break;
+ }
+
+ if ((baddr = inet_parse(s1)) == 0xffffffff ||
+ (baddr & 0xef000000) != 0xef000000) {
+ log(LOG_ERR, 0,
+ "incorrect address %s for tunnel to %s in %s",
+ s1, inet_fmt(rmt_addr, s1), configfilename);
+ continue;
+ }
+
+ v_acl = (struct vif_acl *)malloc(sizeof(struct vif_acl));
+ if (v_acl == NULL)
+ log(LOG_ERR, 0,
+ "out of memory");
+ VAL_TO_MASK(v_acl->acl_mask, n);
+ v_acl->acl_addr = baddr & v_acl->acl_mask;
+
+ /*
+ * link into data structure
+ */
+ v_acl->acl_next = v->uv_acl;
+ v->uv_acl = v_acl;
+ }
+ else {
+ log(LOG_ERR, 0,
+ "invalid keyword (%s) in %s",
+ w, configfilename);
+ break;
+ }
+ }
+ if (!EQUAL(w, "")) continue;
+
+ log(LOG_INFO, 0,
+ "installing %stunnel from %s to %s as vif #%u - rate=%d",
+ v->uv_flags & VIFF_SRCRT? "srcrt " : "",
+ inet_fmt(lcl_addr, s1), inet_fmt(rmt_addr, s2),
+ numvifs, v->uv_rate_limit);
+
+ ++numvifs;
+
+ if (!(ffr.ifr_flags & IFF_UP)) {
+ v->uv_flags |= VIFF_DOWN;
+ vifs_down = TRUE;
+ }
+ }
+
+ else {
+ log(LOG_ERR, 0,
+ "unknown command '%s' in %s", w, configfilename);
+ }
+ }
+
+ close(f);
+}
+
+
+/*
+ * Return a pointer to the next "word" in the string to which '*s' points,
+ * lower-cased and null terminated, and advance '*s' to point beyond the word.
+ * Words are separated by blanks and/or tabs, and the input string is
+ * considered to terminate at a newline, '#' (comment), or null character.
+ * If no words remain, a pointer to a null string ("") is returned.
+ * Warning: This function clobbers the input string.
+ */
+static char *next_word(s)
+ char **s;
+{
+ char *w;
+
+ w = *s;
+ while (*w == ' ' || *w == '\t')
+ ++w;
+
+ *s = w;
+ for(;;) {
+ switch (**s) {
+
+ case ' ' :
+ case '\t' : **s = '\0';
+ ++*s;
+ return (w);
+
+ case '\n' :
+ case '#' : **s = '\0';
+ return (w);
+
+ case '\0' : return (w);
+
+ default : if (isascii(**s) && isupper(**s))
+ **s = tolower(**s);
+ ++*s;
+ }
+ }
+}
diff --git a/usr.sbin/mrouted/defs.h b/usr.sbin/mrouted/defs.h
new file mode 100644
index 0000000..a0a9f4a
--- /dev/null
+++ b/usr.sbin/mrouted/defs.h
@@ -0,0 +1,172 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: defs.h,v 1.8 1994/08/24 23:53:23 thyagara Exp $
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <syslog.h>
+#include <signal.h>
+#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 "dvmrp.h"
+#include "vif.h"
+#include "route.h"
+#include "prune.h"
+
+/*
+ * 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 3 /* increment on local changes or bug fixes, */
+ /* reset to 0 whever PROTOCOL_VERSION increments */
+
+#define MROUTED_LEVEL ( (MROUTED_VERSION << 8) | PROTOCOL_VERSION )
+ /* for IGMP 'group' field of DVMRP messages */
+
+#define DEL_RTE_GROUP 0
+#define DEL_ALL_ROUTES 1
+ /* for Deleting kernel table entries */
+
+/*
+ * External declarations for global variables and functions.
+ */
+extern char recv_buf[MAX_IP_PACKET_LEN];
+extern char send_buf[MAX_IP_PACKET_LEN];
+extern int igmp_socket;
+extern u_long allhosts_group;
+extern u_long dvmrp_group;
+extern u_long 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 char s1[];
+extern char s2[];
+extern char s3[];
+
+extern int errno;
+extern int sys_nerr;
+#ifndef __FreeBSD__
+extern char * sys_errlist[];
+#endif
+
+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 void accept_group_report();
+extern void query_groups();
+extern void probe_for_neighbors();
+extern int update_neighbor();
+extern void accept_neighbor_request();
+
+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_long inet_parse();
+extern int inet_cksum();
+
+extern struct rtentry * determine_route();
+
+extern void init_ktable();
+extern int grplst_mem();
+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 send_prune();
+extern void accept_prune();
+extern int no_entry_exists();
+extern struct ktable * find_src_grp();
+extern int rtr_cnt();
+extern void free_all_prunes();
+extern void age_table_entry();
+extern void dump_cache();
+
+extern void chkgrp_graft();
+extern void accept_graft();
+extern void send_graft_ack();
+extern void send_graft();
+extern void accept_g_ack();
+extern void mtrace();
+
+extern char * malloc();
+extern char * fgets();
+extern FILE * fopen();
+
+#ifndef htonl
+extern u_long htonl();
+extern u_long ntohl();
+#endif
diff --git a/usr.sbin/mrouted/dvmrp.h b/usr.sbin/mrouted/dvmrp.h
new file mode 100644
index 0000000..5decfdb
--- /dev/null
+++ b/usr.sbin/mrouted/dvmrp.h
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: dvmrp.h,v 1.6 1994/08/24 23:53:30 thyagara Exp $
+ */
+
+/*
+ * 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_DOWN 0x10 /* kernel state of interface */
+#define DVMRP_NF_DISABLED 0x20 /* administratively disabled */
+#define DVMRP_NF_QUERIER 0x40 /* I am the subnet's querier */
+
+/*
+ * 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_long)0xe0000004 /* 224.0.0.4 */
+
+#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 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_RATE_LIMIT 0 /* default 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 0000000..7ddf3bc
--- /dev/null
+++ b/usr.sbin/mrouted/igmp.c
@@ -0,0 +1,291 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: igmp.c,v 1.8 1994/08/24 23:53:32 thyagara Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char recv_buf[MAX_IP_PACKET_LEN]; /* input packet buffer */
+char send_buf[MAX_IP_PACKET_LEN]; /* output packet buffer */
+int igmp_socket; /* socket for all network I/O */
+u_long allhosts_group; /* allhosts addr in net order */
+u_long dvmrp_group; /* DVMRP grp addr in net order */
+u_long 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;
+
+ 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);
+}
+
+/* %%% hack for PIM %%% */
+#define IGMP_PIM 0x14
+#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_HOST_MEMBERSHIP_REPORT: return "membership report ";
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT: return "new membership 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: /* %%% hack for 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: return "IGMP trace query ";
+ case IGMP_MTRACE_RESP: 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 vifi_t vifi;
+ register u_long 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 == NULL || dst == NULL)
+ 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:
+ /* we have to do the determination of the querrier router here */
+ return;
+
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
+ accept_group_report(src, dst, group,igmp->igmp_type);
+ return;
+
+ case IGMP_HOST_LEAVE_MESSAGE:
+ leave_group_message(src, dst, group);
+ return;
+
+ case IGMP_DVMRP:
+ 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: /* %%% hack for PIM %%% */
+ return;
+
+ case IGMP_MTRACE:
+ mtrace(src, dst, group, (char *)(igmp+1),
+ igmp->igmp_code, igmpdatalen);
+ return;
+
+ default:
+ log(LOG_INFO, 0,
+ "ignoring unknown IGMP message type %u 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_long src, dst;
+ int type, code;
+ u_long group;
+ int datalen;
+{
+ static struct sockaddr_in sdst = {AF_INET, sizeof 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);
+
+ 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 on %s", inet_fmt(src, s1));
+ }
+
+ 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 0000000..5d7442b
--- /dev/null
+++ b/usr.sbin/mrouted/inet.c
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: inet.c,v 1.4 1993/05/30 01:36:38 deering Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+char s1[16]; /* buffers to hold the string representations */
+char s2[16]; /* of IP addresses, to be passed to inet_fmt() */
+char s3[16]; /* or inet_fmts(). */
+
+
+/*
+ * 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_long naddr;
+{
+ register u_long 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.
+ */
+int inet_valid_subnet(nsubnet, nmask)
+ u_long nsubnet, nmask;
+{
+ register u_long subnet, mask;
+
+ subnet = ntohl(nsubnet);
+ mask = ntohl(nmask);
+
+ if ((subnet & mask) != subnet) return (FALSE);
+
+ if (IN_CLASSA(subnet)) {
+ if (mask < 0xff000000 ||
+ (subnet & 0xff000000) == 0 ||
+ (subnet & 0xff000000) == 0x7f000000) return (FALSE);
+ }
+ else if (IN_CLASSB(subnet)) {
+ if (mask < 0xffff0000) return (FALSE);
+ }
+ else if (IN_CLASSC(subnet)) {
+ if (mask < 0xffffff00) return (FALSE);
+ }
+ else return (FALSE);
+
+ return (TRUE);
+}
+
+
+/*
+ * Convert an IP address in u_long (network) format into a printable string.
+ */
+char *inet_fmt(addr, s)
+ u_long 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.
+ */
+char *inet_fmts(addr, mask, s)
+ u_long addr, mask;
+ char *s;
+{
+ register u_char *a, *m;
+
+ a = (u_char *)&addr;
+ m = (u_char *)&mask;
+
+ if (m[3] != 0) sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]);
+ else if (m[2] != 0) sprintf(s, "%u.%u.%u", a[0], a[1], a[2]);
+ else if (m[1] != 0) sprintf(s, "%u.%u", a[0], a[1]);
+ else sprintf(s, "%u", a[0]);
+
+ 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_long inet_parse(s)
+ char *s;
+{
+ u_long a;
+ 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 0000000..a44a15f
--- /dev/null
+++ b/usr.sbin/mrouted/kern.c
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: kern.c,v 1.6 1994/08/24 23:53:37 thyagara Exp $
+ */
+
+
+#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_long 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_long grp;
+ u_long 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_long grp;
+ u_long 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()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_INIT,
+ (char *)NULL, 0) < 0)
+ log(LOG_ERR, errno, "can't enable DVMRP routing in kernel");
+}
+
+
+void k_stop_dvmrp()
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DONE,
+ (char *)NULL, 0) < 0)
+ log(LOG_WARNING, errno, "can't disable DVMRP 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, DVMRP_ADD_VIF,
+ (char *)&vc, sizeof(vc)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_ADD_VIF");
+}
+
+
+void k_del_vif(vifi)
+ vifi_t vifi;
+{
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_VIF,
+ (char *)&vifi, sizeof(vifi)) < 0)
+ log(LOG_ERR, errno, "setsockopt DVMRP_DEL_VIF");
+}
+
+
+/*
+ * Adds a (source, mcastgrp) entry to the kernel
+ */
+void k_add_rg(kt)
+ struct ktable *kt;
+{
+ struct mfcctl mc;
+
+ /* copy table values so that setsockopt can process it */
+ COPY_TABLES(kt, mc);
+
+ /* write to kernel space */
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_ADD_MFC,
+ (char *)&mc, sizeof(mc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_ADD_MFC");
+}
+
+
+/*
+ * Deletes a (source, mcastgrp) entry from the kernel
+ */
+void k_del_rg(kt)
+ struct ktable *kt;
+{
+ struct mfcctl mc;
+
+ /* copy table values so that setsockopt can process it */
+ COPY_TABLES(kt, mc);
+
+ /* write to kernel space */
+ if (setsockopt(igmp_socket, IPPROTO_IP, DVMRP_DEL_MFC,
+ (char *)&mc, sizeof(mc)) < 0)
+ log(LOG_WARNING, errno, "setsockopt DVMRP_DEL_MFC");
+}
diff --git a/usr.sbin/mrouted/main.c b/usr.sbin/mrouted/main.c
new file mode 100644
index 0000000..22a0214
--- /dev/null
+++ b/usr.sbin/mrouted/main.c
@@ -0,0 +1,439 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: main.c,v 1.8 1994/08/24 23:53:42 thyagara Exp $
+ */
+
+/*
+ * 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"
+
+extern char *configfilename;
+
+static char pidfilename[] = "/etc/mrouted.pid";
+static char dumpfilename[] = "/usr/tmp/mrouted.dump";
+static char cachefilename[] = "/usr/tmp/mrouted.cache";
+static char genidfilename[] = "/usr/tmp/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 */
+
+
+/*
+ * Forward declarations.
+ */
+static void fasttimer();
+static void timer();
+static void hup();
+static void dump();
+static void fdump();
+static void cdump();
+static void restart();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register int recvlen;
+ register int omask;
+ int dummy;
+ FILE *fp;
+ extern uid_t geteuid();
+ struct timeval tv;
+ struct timezone tzp;
+ u_long prev_genid;
+
+ setlinebuf(stderr);
+
+ 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);
+ t = open("/dev/tty", 2);
+ if (t >= 0) {
+ (void)ioctl(t, TIOCNOTTY, (char *)0);
+ (void)close(t);
+ }
+ }
+ 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);
+
+ srandom(gethostid());
+
+ /*
+ * Get generation id
+ */
+ gettimeofday(&tv, &tzp);
+ 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();
+ init_igmp();
+ k_init_dvmrp(); /* enable DVMRP routing in kernel */
+ init_routes();
+ init_ktable();
+ init_vifs();
+
+ 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, hup);
+ (void)signal(SIGINT, hup);
+ (void)signal(SIGUSR1, fdump);
+ (void)signal(SIGUSR2, cdump);
+ if (debug != 0)
+ (void)signal(SIGQUIT, dump);
+
+ (void)alarm(1); /* schedule first timer interrupt */
+
+ /*
+ * Main receive loop.
+ */
+ dummy = 0;
+ for(;;) {
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 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);
+ }
+}
+
+
+/*
+ * routine invoked every second. It's 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);
+ }
+
+ /*
+ * Advance virtual time
+ */
+ virtual_time += TIMER_INTERVAL;
+}
+
+
+/*
+ * On hangup signal, let everyone know we're going away.
+ */
+static void hup()
+{
+ log(LOG_INFO, 0, "hup");
+ expire_all_routes();
+ report_to_all_neighbors(ALL_ROUTES);
+ exit(1);
+}
+
+
+/*
+ * 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_INFO, 0, "restart");
+
+ /*
+ * reset all the entries
+ */
+ omask = sigblock(sigmask(SIGALRM));
+ free_all_prunes();
+ free_all_routes();
+ stop_all_vifs();
+ k_stop_dvmrp();
+
+ /*
+ * 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.
+ */
+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: break;
+ case 1: if (severity > LOG_NOTICE) break;
+ case 2: if (severity > LOG_INFO ) break;
+ 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_NOTICE) {
+ fmt[0] = '\0';
+ if (severity == LOG_WARNING) strcat(fmt, "warning - ");
+ strncat(fmt, format, 80);
+ if (syserr != 0) {
+ strcat(fmt, ": %m");
+ errno = syserr;
+ }
+ syslog(severity, fmt, a, b, c, d, e);
+
+ if (severity <= LOG_ERR) exit(-1);
+ }
+}
diff --git a/usr.sbin/mrouted/map-mbone/Makefile b/usr.sbin/mrouted/map-mbone/Makefile
new file mode 100644
index 0000000..4303cf2
--- /dev/null
+++ b/usr.sbin/mrouted/map-mbone/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+PROG= map-mbone
+
+S= ${.CURDIR}/..
+.PATH: $S
+CFLAGS+= -I$S
+LDADD+= -lmrouted
+.if exists($S/common/obj)
+LDDESTDIR+= -L$S/common/obj
+DPADD+= $S/common/obj/libmrouted.a
+.else
+LDDESTDIR+= -L$S/common
+DPADD+= $S/common/libmrouted.a
+.endif
+
+SRCS= mapper.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/mapper.c b/usr.sbin/mrouted/mapper.c
new file mode 100644
index 0000000..5dba17c
--- /dev/null
+++ b/usr.sbin/mrouted/mapper.c
@@ -0,0 +1,954 @@
+/* Mapper for connections between MRouteD multicast routers.
+ * Written by Pavel Curtis <Pavel@PARC.Xerox.Com>
+ *
+ * $Id: mapper.c,v 1.8 1994/08/24 23:53:54 thyagara Exp $
+ */
+
+/*
+ * 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 <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_long 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_long addr; /* IP address of the interface in NET order */
+ Neighbor *neighbors; /* List of neighbors' IP addresses */
+} Interface;
+
+typedef struct node {
+ u_long addr; /* IP address of this entry in NET order */
+ u_long 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_long 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_long 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_long 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_long 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_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void ask2(dst)
+ u_long 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_long 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_long 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_long 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_long 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_long 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_long 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_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*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_long 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_long 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_long 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_long 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_long*)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_long 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_long*)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_long 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_long 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()
+{
+ u_long 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_long 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;
+}
+
+
+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;
+ addr.sin_len = sizeof addr;
+ 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, sizeof(recv_buf),
+ 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 leave_group_message()
+{
+}
+void mtrace()
+{
+}
diff --git a/usr.sbin/mrouted/mrinfo.c b/usr.sbin/mrouted/mrinfo.c
new file mode 100644
index 0000000..a24a2e3
--- /dev/null
+++ b/usr.sbin/mrouted/mrinfo.c
@@ -0,0 +1,481 @@
+/*
+ * 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[] =
+ "@(#) $Id: mrinfo.c,v 1.7 1994/08/24 23:54:04 thyagara Exp $";
+/* original rcsid:
+ "@(#) Header: mrinfo.c,v 1.6 93/04/08 15:14:16 van Exp (LBL)";
+*/
+#endif
+
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 4 /* How long to wait before retrying requests */
+#define DEFAULT_RETRIES 3 /* How many times to ask each router */
+
+u_long our_addr, target_addr = 0; /* in NET order */
+int debug = 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_long addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? 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_long dst;
+{
+ send_igmp(our_addr, dst, IGMP_DVMRP, DVMRP_ASK_NEIGHBORS,
+ htonl(MROUTED_LEVEL), 0);
+}
+
+void
+ask2(dst)
+ u_long 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_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+#define GET_ADDR(a) (a = ((u_long)*p++ << 24), a += ((u_long)*p++ << 16),\
+ a += ((u_long)*p++ << 8), a += *p++)
+
+ printf("%s (%s):\n", inet_fmt(src, s1), inet_name(src));
+ while (p < ep) {
+ register u_long 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_long 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_long src, dst;
+ u_char *p;
+ int datalen;
+{
+ u_char *ep = p + datalen;
+
+ 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_long laddr = *(u_long*)p;
+
+ p += 4;
+ metric = *p++;
+ thresh = *p++;
+ flags = *p++;
+ ncount = *p++;
+ while (--ncount >= 0) {
+ register u_long neighbor = *(u_long*)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_QUERIER)
+ printf("/querier");
+ if (flags & DVMRP_NF_DISABLED)
+ printf("/disabled");
+ if (flags & DVMRP_NF_DOWN)
+ printf("/down");
+ 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_long
+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;
+}
+
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ setlinebuf(stderr);
+
+ 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 '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 || (argc == 1 && !(target_addr = host_addr(argv[0])))) {
+usage: fprintf(stderr,
+ "Usage: mrinfo [-t timeout] [-r retries] router\n");
+ exit(1);
+ }
+ if (target_addr == 0)
+ goto usage;
+ 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;
+ addr.sin_len = sizeof addr;
+ 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_long 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, sizeof(recv_buf),
+ 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;
+ src = ip->ip_src.s_addr;
+ 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;
+ }
+ 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:
+ 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 leave_group_message()
+{
+}
+void mtrace()
+{
+}
diff --git a/usr.sbin/mrouted/mrinfo/Makefile b/usr.sbin/mrouted/mrinfo/Makefile
new file mode 100644
index 0000000..bc444ac
--- /dev/null
+++ b/usr.sbin/mrouted/mrinfo/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+PROG= mrinfo
+
+S= ${.CURDIR}/..
+.PATH: $S
+CFLAGS+= -I$S
+LDADD+= -lmrouted
+.if exists($S/common/obj)
+LDDESTDIR+= -L$S/common/obj
+DPADD+= $S/common/obj/libmrouted.a
+.else
+LDDESTDIR+= -L$S/common
+DPADD+= $S/common/libmrouted.a
+.endif
+
+SRCS= mrinfo.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/mrouted.8 b/usr.sbin/mrouted/mrouted.8
new file mode 100644
index 0000000..5b9ee96
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.8
@@ -0,0 +1,319 @@
+'\"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 supports IP source route tunnelling only for backwards
+compatibility.
+.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.
+.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 <scoped-addr>/<mask-len>]
+
+ tunnel <local-addr> <remote-addr> [metric <m>]
+ [threshold <t>] [srcrt] [rate_limit <b>]
+ [boundary <scoped-addr>/<mask-len>]
+
+ cache_lifetime <ct>
+
+ pruning <off/on>
+
+.fi
+.PP
+One note about the configuration commands - all the phyint and tunnel
+command options must be on a single line except for the boundary option
+which may begin on a separate line. A single phyint or tunnel command may
+have multiple boundary options.
+.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) for the phyint command only.
+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
+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.
+.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.
+.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 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).
+.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 In-Vif Out-Vifs
+ 36.2 1 0 1* 2 3*
+ 36.8 36.8.0.77 4 2 0* 1* 3*
+ 36.11 1 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 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 (325 entries)
+ Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs
+ 134.207.7 224.2.140.239 300 1 0 0 2
+ 138.15.103 224.2.203.214 295 1 2 P 0p 2p
+ 128.237.0 224.2.253.119 290 1 1 0 2p
+ 129.215.200 224.2.207.48 40 1 1 0p 2
+ 36.77.14 239.0.1.234 345 2b
+
+.fi
+Each entry is characterized by the origin subnet number and the
+destination multicast group. The 'CTmr' field indicates the lifetime
+(in seconds) of the entry. The entry is deleted from the cache table
+when the timer decrements to zero. 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" in the Psnt field. 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.
+
+
+.SH FILES
+/etc/mrouted.conf
+.SH SEE ALSO
+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
diff --git a/usr.sbin/mrouted/mrouted.conf b/usr.sbin/mrouted/mrouted.conf
new file mode 100644
index 0000000..5340bfc
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted.conf
@@ -0,0 +1,26 @@
+# $Id: mrouted.conf,v 1.5 1994/08/24 23:54:21 thyagara Exp $
+#
+# This is the configuration file for "mrouted", an IP multicast router.
+# mrouted looks for it in "/etc/mrouted.conf".
+#
+# Command formats:
+#
+# cache_lifetime 3600
+# pruning on
+#
+# phyint <local-addr> [disable] [metric <m>] [threshold <t>] [rate_limit <b>]
+# [boundary <scoped-addr>/<mask-len>]
+# tunnel <local-addr> <remote-addr> [srcrt] [metric <m>]
+# [threshold <t>] [rate_limit <b>]
+# [boundary <scoped-addr>/<mask-len>]
+#
+# NOTE: any phyint commands MUST precede any tunnel commands
+# NOTE: boundary commands may appear on a separate line
+# (OTHER keywords must be on the same line as phyint or tunnel)
+# NOTE: the mask-len is the no. of leading 1's in the mask
+#
+
+phyint 128.4.2.2 metric 1 threshold 16 boundary 239.2.0.0/16
+ boundary 239.5.8.0/24
+tunnel 128.4.0.77 128.4.0.8 metric 3 rate_limit 500 # <-- EXAMPLE
+ boundary 239.2.3.3/16 # 239.2.x.x is scoped
diff --git a/usr.sbin/mrouted/mrouted/Makefile b/usr.sbin/mrouted/mrouted/Makefile
new file mode 100644
index 0000000..12c4495
--- /dev/null
+++ b/usr.sbin/mrouted/mrouted/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+PROG= mrouted
+
+S= ${.CURDIR}/..
+.PATH: $S
+CFLAGS+= -I$S
+LDADD+= -lmrouted
+.if exists($S/common/obj)
+LDDESTDIR+= -L$S/common/obj
+DPADD+= $S/common/obj/libmrouted.a
+.else
+LDDESTDIR+= -L$S/common
+DPADD+= $S/common/libmrouted.a
+.endif
+
+SRCS= config.c main.c route.c vif.c prune.c callout.c
+MAN8= ${.CURDIR}/../mrouted.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/mtrace.c b/usr.sbin/mrouted/mtrace.c
new file mode 100644
index 0000000..5a8870e
--- /dev/null
+++ b/usr.sbin/mrouted/mtrace.c
@@ -0,0 +1,460 @@
+#include <netdb.h>
+#include <sys/time.h>
+#include "defs.h"
+
+#define DEFAULT_TIMEOUT 10 /* How long to wait before retrying requests */
+
+int timeout = DEFAULT_TIMEOUT;
+
+vifi_t numvifs; /* to keep loader happy */
+ /* (see COPY_TABLES macro called in kern.c) */
+
+
+char *
+inet_name(addr)
+ u_long addr;
+{
+ struct hostent *e;
+
+ e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
+
+ return e ? e->h_name : "?";
+}
+
+u_long
+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;
+}
+char *
+proto_type(type)
+ u_char type;
+{
+ switch (type) {
+ case PROTO_DVMRP:
+ return ("PROTO_DVMRP");
+ case PROTO_MOSPF:
+ return ("PROTO_MOSPF");
+ case PROTO_PIM:
+ return ("PROTO_PIM");
+ case PROTO_CBT:
+ return ("PROTO_CBT");
+ default:
+ return ("PROTO_UNKNOWN");
+ }
+}
+
+char *
+flag_type(type)
+ u_char type;
+{
+ switch (type) {
+ case TR_NO_ERR:
+ return ("NO_ERR");
+ case TR_WRONG_IF:
+ return ("WRONG_IF");
+ case TR_PRUNED:
+ return ("PRUNED");
+ case TR_SCOPED:
+ return ("SCOPED");
+ case TR_NO_RTE:
+ return ("NO_RTE");
+ default:
+ return ("INVALID ERR");
+ }
+}
+
+int
+t_diff(a_sec, a_usec, b_sec, b_usec)
+ u_long a_sec, a_usec, b_sec, b_usec;
+{
+ int d = a_sec - b_sec;
+ int ms = a_usec - b_usec;
+
+ if ((d < 0) ||
+ ((d == 0) && (ms < 0))) {
+ d = b_sec - a_sec;
+ ms = b_usec - a_usec;
+ }
+
+ switch (d) {
+ case 0:
+ break;
+ case 2:
+ ms += 1000000;
+ case 1:
+ ms += 1000000;
+ break;
+ default:
+ ms += (1000000) * d;
+ }
+ return (ms/1000);
+}
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ struct timeval tq;
+ struct timezone tzp;
+ u_long resptime;
+
+ int udp;
+ struct sockaddr_in addr;
+ int addrlen = sizeof(addr);
+ u_long lcl_addr = 0; /* in NET order */
+
+ u_long qid = ((u_long)random() >> 8);
+ u_long qsrc = NULL;
+ u_long qgrp = NULL;
+ u_long qdst = NULL;
+ u_char qno = 0;
+ u_long raddr = NULL;
+ u_char qttl = 1;
+ u_char rttl = 1;
+ u_long dst = NULL;
+
+ struct tr_query *query;
+
+ struct tr_rlist *tr_rlist = NULL;
+
+ char *p;
+ int datalen = 0;
+
+ int i;
+ int done = 0;
+
+ argv++, argc--;
+
+ while (argc > 0 && *argv[0] == '-') {
+ switch (argv[0][1]) {
+ case 's':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ qsrc = host_addr(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 'g':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ qgrp = host_addr(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 'd':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ qdst = host_addr(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 'x':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ dst = host_addr(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 't':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ qttl = atoi(argv[0]);
+ if (qttl < 1)
+ qttl = 1;
+ break;
+ } else
+ goto usage;
+ case 'n':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ qno = atoi(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 'l':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ rttl = atoi(argv[0]);
+ break;
+ } else
+ goto usage;
+ case 'r':
+ if (argc > 1 && isdigit(*(argv + 1)[0])) {
+ argv++, argc--;
+ raddr = host_addr(argv[0]);
+ break;
+ } else
+ goto usage;
+ default:
+ goto usage;
+ }
+ argv++, argc--;
+ }
+
+ if (argc > 0) {
+usage: printf("usage: mtrace -s <src> -g <grp> -d <dst> -n <# reports> \n");
+ printf(" -t <ttl> [-x <qdst>] [-r <rdst>] [-l <rttl>]\n");
+ exit(1);
+ }
+
+ printf("Mtrace src %s grp %s dst %s #%d\n", inet_fmt(qsrc, s1),
+ inet_fmt(qgrp, s2), inet_fmt(qdst, s3), qno);
+ printf(" resp ttl %d resp addr %s\n", rttl, inet_fmt(raddr, s1));
+
+ init_igmp();
+
+ /* Obtain the local address from which to send out packets */
+
+ addr.sin_family = AF_INET;
+ addr.sin_len = sizeof addr;
+ addr.sin_addr.s_addr = qgrp;
+ addr.sin_port = htons(2000);
+
+ 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);
+ lcl_addr = addr.sin_addr.s_addr;
+
+ /* Got the local address now */
+ /* Now, make up the IGMP packet to send */
+
+ query = (struct tr_query *)(send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN);
+
+ query->tr_src = qsrc;
+ query->tr_dst = qdst;
+ query->tr_qid = qid;
+ if (raddr)
+ query->tr_raddr = raddr;
+ else
+ query->tr_raddr = lcl_addr;
+ query->tr_rttl = rttl;
+
+ datalen += sizeof(struct tr_query);
+
+ if (IN_MULTICAST(ntohl(qgrp)))
+ k_set_ttl(qttl);
+ else
+ k_set_ttl(1);
+
+ if (dst == NULL)
+ dst = qgrp;
+
+ /*
+ * set timer to calculate delays & send query
+ */
+ gettimeofday(&tq, &tzp);
+
+ send_igmp(lcl_addr, dst, IGMP_MTRACE, qno,
+ qgrp, datalen);
+
+ /*
+ * If the response is to be a multicast address, make sure we
+ * are listening on that multicast address.
+ */
+ if (IN_MULTICAST(ntohl(raddr)))
+ k_join(raddr, lcl_addr);
+
+ /* Wait for our reply now */
+ while (!done) {
+ fd_set fds;
+ struct timeval tv;
+ struct timezone tzp;
+
+ int count, recvlen, dummy = 0;
+ register u_long src, dst, group, smask;
+ struct ip *ip;
+ struct igmp *igmp;
+ struct tr_resp *resp;
+ int ipdatalen, iphdrlen, igmpdatalen;
+ int rno;
+
+ FD_ZERO(&fds);
+ FD_SET(igmp_socket, &fds);
+
+ /* need to input timeout as optional argument */
+ 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) {
+ printf("Timed out receiving responses\n");
+ exit(1);
+ }
+
+ recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf),
+ 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;
+
+ iphdrlen = ip->ip_hl << 2;
+ ipdatalen = ip->ip_len;
+ if (iphdrlen + ipdatalen != recvlen) {
+ printf("packet shorter (%u bytes) than hdr+data length (%u+%u)\n",
+ recvlen, iphdrlen, ipdatalen);
+ continue;
+ }
+
+ igmp = (struct igmp *) (recv_buf + iphdrlen);
+ group = igmp->igmp_group.s_addr;
+ igmpdatalen = ipdatalen - IGMP_MINLEN;
+ if (igmpdatalen < 0) {
+ printf("IP data field too short (%u bytes) for IGMP, from %s\n",
+ ipdatalen, inet_fmt(src, s1));
+ continue;
+ }
+
+ if (igmp->igmp_type != IGMP_MTRACE &&
+ igmp->igmp_type != IGMP_MTRACE_RESP)
+ continue;
+
+ if (igmpdatalen == QLEN)
+ continue;
+
+ if ((igmpdatalen - QLEN)%RLEN) {
+ printf("packet with incorrect datalen\n");
+ continue;
+ }
+
+ query = (struct tr_query *)(igmp + 1);
+
+ /* If this is query with a different id, ignore! */
+ if (query->tr_qid != qid)
+ continue;
+
+ /*
+ * Most of the sanity checking done at this point.
+ * This is the packet we have been waiting for all this time
+ */
+ resp = (struct tr_resp *)(query + 1);
+
+ rno = (igmpdatalen - QLEN)/RLEN;
+
+ /*
+ * print the responses out in reverse order (from src to dst)
+ */
+ printf("src: <%s> grp: <%s> dst: <%s>\n\n", inet_fmt(qsrc, s1),
+ inet_fmt(qgrp, s2), inet_fmt(qdst, s3));
+
+ VAL_TO_MASK(smask, (resp+rno-1)->tr_smask);
+
+ if (((resp+rno-1)->tr_inaddr & smask) == (qsrc & smask))
+ printf(" %-15s \n", inet_fmt(qsrc, s1));
+ else
+ printf(" * * *\n");
+
+ resptime = 0;
+ while (rno--) {
+ struct tr_resp *r = resp + rno;
+
+ printf(" | \n");
+ printf(" %-15s ", inet_fmt(r->tr_inaddr, s1));
+ printf("ttl %d ", r->tr_fttl);
+ printf("cum: %d ms ",
+ t_diff(r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4,
+ tq.tv_sec & 0xffff, tq.tv_usec));
+ printf("hop: %d ms ",
+ t_diff(resptime >> 16, (resptime & 0xffff) << 4,
+ r->tr_qarr >> 16, (r->tr_qarr & 0xffff) << 4));
+ printf("%s ", proto_type(r->tr_rproto));
+ printf("%s\n", flag_type(r->tr_rflags));
+
+ printf(" %-15s ", inet_fmt(r->tr_outaddr, s1));
+ printf("v_in: %ld ", r->tr_vifin);
+ printf("v_out: %ld ", r->tr_vifout);
+ printf("pkts: %ld\n", r->tr_pktcnt);
+
+ resptime = r->tr_qarr;
+ }
+ printf(" | \n");
+ printf(" %-15s \n", inet_fmt(qdst, s1));
+
+ /*
+ * if the response was multicast back, leave the group
+ */
+ if (IN_MULTICAST(ntohl(raddr)))
+ k_leave(raddr, lcl_addr);
+
+ /* If I don't expect any more replies, exit here */
+ exit(0);
+ }
+}
+/* dummies */
+void log()
+{
+}
+void accept_probe()
+{
+}
+void accept_group_report()
+{
+}
+void accept_neighbors()
+{
+}
+void accept_neighbors2()
+{
+}
+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 mtrace()
+{
+}
+void leave_group_message()
+{
+}
diff --git a/usr.sbin/mrouted/mtrace/Makefile b/usr.sbin/mrouted/mtrace/Makefile
new file mode 100644
index 0000000..2dd538b
--- /dev/null
+++ b/usr.sbin/mrouted/mtrace/Makefile
@@ -0,0 +1,20 @@
+# $Id$
+
+PROG= mtrace
+
+S= ${.CURDIR}/..
+.PATH: $S
+CFLAGS+= -I$S
+LDADD+= -lmrouted
+.if exists($S/common/obj)
+LDDESTDIR+= -L$S/common/obj
+DPADD+= $S/common/obj/libmrouted.a
+.else
+LDDESTDIR+= -L$S/common
+DPADD+= $S/common/libmrouted.a
+.endif
+
+SRCS= mtrace.c
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mrouted/prune.c b/usr.sbin/mrouted/prune.c
new file mode 100644
index 0000000..04387a1
--- /dev/null
+++ b/usr.sbin/mrouted/prune.c
@@ -0,0 +1,1370 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: prune.c,v 1.4 1994/08/24 23:54:33 thyagara Exp $
+ */
+
+
+#include "defs.h"
+
+extern int cache_lifetime;
+extern int max_prune_lifetime;
+
+/*
+ * dither cache lifetime to obtain a value between x and 2*x
+ */
+#define CACHE_LIFETIME(x) ((x) + (random() % (x)))
+
+#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; \
+ } \
+ }
+
+static struct ktable *kernel_rtable; /* ptr to list of kernel rt entries */
+unsigned int kroutes; /* current number of cache entries */
+
+
+/*
+ * Initialize the kernel table structure
+ */
+void init_ktable()
+{
+ kernel_rtable = NULL;
+ kroutes = 0;
+}
+
+/*
+ * Determine if mcastgrp has a listener on vifi
+ */
+int grplst_mem(vifi, mcastgrp)
+ vifi_t vifi;
+ u_long 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;
+}
+
+/*
+ * Updates the ttl values for each vif.
+ */
+void prun_add_ttls(kt)
+ struct ktable *kt;
+{
+ struct uvif *v;
+ vifi_t vifi;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (VIFM_ISSET(vifi, kt->kt_grpmems))
+ kt->kt_ttls[vifi] = v->uv_threshold;
+ else
+ kt->kt_ttls[vifi] = NULL;
+ }
+}
+
+/*
+ * checks for scoped multicast addresses
+ */
+#define GET_SCOPE(kt) { \
+ register int _i; \
+ if (((kt)->kt_mcastgrp & 0xff000000) == 0xef000000) \
+ for (_i = 0; _i < numvifs; _i++) \
+ if (scoped_addr(_i, (kt)->kt_mcastgrp)) \
+ VIFM_SET(_i, (kt)->kt_scope); \
+ }
+
+int scoped_addr(vifi, addr)
+ vifi_t vifi;
+ u_long 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;
+}
+
+/*
+ * Add a new table entry for (origin, mcastgrp)
+ */
+void add_table_entry(origin, mcastgrp)
+ u_long origin;
+ u_long mcastgrp;
+{
+ struct rtentry *r;
+ struct ktable *kt;
+ int i;
+
+ if ((kt = find_src_grp(origin, mcastgrp)) != NULL) {
+ log(LOG_DEBUG, 0, "kernel entry exists for (%s %s)",
+ inet_fmt(origin, s1), inet_fmt(mcastgrp, s2));
+ return;
+ }
+
+ r = determine_route(origin);
+
+ /* allocate space for the new entry */
+ kt = (struct ktable *)malloc(sizeof(struct ktable));
+ if (kt == NULL)
+ log(LOG_ERR, 0, "ran out of memory"); /* fatal */
+
+ kroutes++;
+
+ /* add the new values in */
+ if (r == NULL) {
+ kt->kt_origin = origin;
+ kt->kt_mcastgrp = mcastgrp;
+ kt->kt_originmask = 0xffffffff;
+ kt->kt_parent = NO_VIF;
+ kt->kt_gateway = 0;
+ kt->kt_children = 0;
+ kt->kt_leaves = 0;
+ kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ kt->kt_grpmems = 0;
+ kt->kt_rlist = NULL;
+ kt->kt_prsent_timer = 0;
+ kt->kt_grftsnt = 0;
+ kt->kt_prun_count = 0;
+ kt->kt_scope = 0;
+ }
+ else {
+ kt->kt_origin = r->rt_origin;
+ kt->kt_mcastgrp = mcastgrp;
+ kt->kt_originmask = r->rt_originmask;
+ kt->kt_parent = r->rt_parent;
+ kt->kt_gateway = r->rt_gateway;
+ kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ kt->kt_grpmems = 0;
+ kt->kt_rlist = NULL;
+ kt->kt_prsent_timer = 0;
+ kt->kt_grftsnt = 0;
+ kt->kt_prun_count = 0;
+ kt->kt_scope = 0;
+
+ VIFM_COPY(r->rt_children, kt->kt_children);
+ VIFM_COPY(r->rt_leaves, kt->kt_leaves);
+
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, kt->kt_children) &&
+ !(VIFM_ISSET(i, kt->kt_leaves)))
+ VIFM_SET(i, kt->kt_grpmems);
+
+ if (VIFM_ISSET(i, kt->kt_leaves) && grplst_mem(i, mcastgrp))
+ VIFM_SET(i, kt->kt_grpmems);
+ }
+ GET_SCOPE(kt);
+ if (VIFM_ISSET(kt->kt_parent, kt->kt_scope))
+ kt->kt_grpmems = NULL;
+ else
+ kt->kt_grpmems &= ~kt->kt_scope;
+ }
+
+ /* update the kernel_rtable pointer */
+ kt->kt_next = kernel_rtable;
+ kernel_rtable = kt;
+
+ /* update ttls and add entry into kernel */
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+
+ log(LOG_DEBUG, 0, "add entry s:%x g:%x gm:%x",
+ kt->kt_origin, kt->kt_mcastgrp, kt->kt_grpmems);
+
+ /* If there are no leaf vifs
+ * which have this group, then
+ * mark this src-grp as a prune candidate.
+ * One thing to do is to check if parent vif is the source
+ * and not send a prune to that.
+ */
+ if (!kt->kt_grpmems && kt->kt_gateway)
+ send_prune(kt);
+}
+
+/*
+ * 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_long addr;
+{
+ struct ktable *prev_kt, *kt;
+ struct prunlst *prev_krl, *krl;
+
+ /* Check each src-grp entry to see if it was pruned on that interface
+ If so, forward on that interface */
+ for (prev_kt = (struct ktable *)&kernel_rtable,
+ kt = kernel_rtable; kt;
+ prev_kt = kt, kt = kt->kt_next) {
+ for (prev_krl = (struct prunlst *)&kt->kt_rlist,
+ krl = prev_krl->rl_next;
+ krl;
+ prev_krl = krl, krl = krl->rl_next) {
+ if (krl->rl_router == addr) {
+ prev_krl->rl_next = krl->rl_next;
+ free(krl);
+ krl = prev_krl;
+ kt->kt_prun_count--;
+ }
+ }
+
+ /*
+ * If neighbor was the parent, remove the prune sent state
+ * Don't send any grafts upstream.
+ */
+ if (vifi == kt->kt_parent) {
+ k_del_rg(kt);
+ prev_kt->kt_next = kt->kt_next;
+ while (krl = kt->kt_rlist) {
+ kt->kt_rlist = krl->rl_next;
+ free((char *)krl);
+ }
+ free((char *)kt);
+ kt = prev_kt;
+ kroutes--;
+ continue;
+ }
+
+ /*
+ * Neighbor was not the parent, send grafts to join the groups
+ */
+ if (kt->kt_prsent_timer) {
+ kt->kt_grftsnt = 1;
+ send_graft(kt);
+ kt->kt_prsent_timer = 0;
+ }
+
+ if (!VIFM_ISSET(vifi, kt->kt_grpmems)) {
+ if (VIFM_ISSET(vifi, kt->kt_children) &&
+ !(VIFM_ISSET(vifi, kt->kt_leaves)))
+ VIFM_SET(vifi, kt->kt_grpmems);
+
+ if (VIFM_ISSET(vifi, kt->kt_leaves) &&
+ grplst_mem(vifi, kt->kt_mcastgrp))
+ VIFM_SET(vifi, kt->kt_grpmems);
+
+ kt->kt_grpmems &= ~kt->kt_scope;
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ }
+ }
+}
+
+/*
+ * 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_long mcastgrp;
+ u_int del_flag;
+{
+ struct mfcctl mc;
+ struct ktable *kt, *prev_kt;
+ struct prunlst *krl;
+
+ if (del_flag == DEL_ALL_ROUTES) {
+ for (prev_kt = (struct ktable *)&kernel_rtable;
+ kt = prev_kt->kt_next;
+ prev_kt = kt) {
+ if ((kt->kt_origin & r->rt_originmask) == r->rt_origin) {
+ log(LOG_DEBUG, 0, "delete all rtes %x grp %x",
+ kt->kt_origin, mcastgrp);
+
+ k_del_rg(kt);
+
+ /* free prun list entries */
+ while (kt->kt_rlist) {
+ krl = kt->kt_rlist;
+ kt->kt_rlist = krl->rl_next;
+ free((char *)krl);
+ }
+
+ /* free the source mcastgrp entry */
+ prev_kt->kt_next = kt->kt_next;
+ free((char *)kt);
+ kroutes--;
+ kt = prev_kt;
+ }
+ }
+ }
+
+ if (del_flag == DEL_RTE_GROUP) {
+ for (prev_kt = (struct ktable *)&kernel_rtable;
+ (prev_kt) && (kt = prev_kt->kt_next);
+ prev_kt = kt) {
+ if ((kt->kt_origin & r->rt_originmask) == r->rt_origin &&
+ kt->kt_mcastgrp == mcastgrp) {
+ log(LOG_DEBUG, 0, "delete src %x grp %x",
+ kt->kt_origin, mcastgrp);
+
+ k_del_rg(kt);
+
+ /* free prun list entries */
+ while (kt->kt_rlist) {
+ krl = kt->kt_rlist;
+ kt->kt_rlist = krl->rl_next;
+ free((char *)krl);
+ }
+
+ /* free the source mcastgrp entry */
+ prev_kt->kt_next = kt->kt_next;
+ free((char *)kt);
+ kroutes--;
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * update kernel table entry when a route entry changes
+ */
+void update_table_entry(r)
+ struct rtentry *r;
+{
+ struct ktable *kt;
+ struct prunlst *krl;
+ int i;
+ int changed;
+
+ for (kt = kernel_rtable; kt; kt = kt->kt_next)
+ if ((kt->kt_origin & r->rt_originmask)== r->rt_origin) {
+ changed = 0;
+
+ if (kt->kt_leaves != r->rt_leaves)
+ changed++;
+ if (kt->kt_children != r->rt_children)
+ changed++;
+ if (kt->kt_parent != r->rt_parent)
+ changed++;
+
+ if (!changed)
+ continue;
+
+ log(LOG_DEBUG, 0, "update entry: s %-15s g %-15s",
+ inet_fmt(kt->kt_origin, s1), inet_fmt(kt->kt_mcastgrp, s2));
+
+ /* free prun list entries */
+ while (kt->kt_rlist) {
+ krl = kt->kt_rlist;
+ kt->kt_rlist = krl->rl_next;
+ free((char *)krl);
+ }
+
+ kt->kt_parent = r->rt_parent;
+ kt->kt_gateway = r->rt_gateway;
+ kt->kt_grpmems = 0;
+ kt->kt_prun_count = 0;
+ VIFM_COPY(r->rt_children, kt->kt_children);
+ VIFM_COPY(r->rt_leaves, kt->kt_leaves);
+
+ /* obtain the multicast group membership list */
+ for (i = 0; i < numvifs; i++) {
+ if (VIFM_ISSET(i, kt->kt_children) &&
+ !(VIFM_ISSET(i, kt->kt_leaves)))
+ VIFM_SET(i, kt->kt_grpmems);
+
+ if (VIFM_ISSET(i, kt->kt_leaves) && grplst_mem(i, kt->kt_mcastgrp))
+ VIFM_SET(i, kt->kt_grpmems);
+ }
+ if (VIFM_ISSET(kt->kt_parent, kt->kt_scope))
+ kt->kt_grpmems = NULL;
+ else
+ kt->kt_grpmems &= ~kt->kt_scope;
+
+ if (kt->kt_grpmems && kt->kt_prsent_timer) {
+ kt->kt_grftsnt = 1;
+ send_graft(kt);
+ kt->kt_prsent_timer = 0;
+ }
+
+ /* update ttls and add entry into kernel */
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+
+ if (!kt->kt_grpmems && kt->kt_gateway) {
+ kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ send_prune(kt);
+ }
+ }
+}
+
+
+
+/*
+ * set the forwarding flag for all mcastgrps on this vifi
+ */
+void update_lclgrp(vifi, mcastgrp)
+ vifi_t vifi;
+ u_long mcastgrp;
+{
+ struct ktable *kt;
+
+ log(LOG_DEBUG, 0, "group %x joined at vif %d", mcastgrp, vifi);
+
+ for (kt = kernel_rtable; kt; kt = kt->kt_next)
+ if (kt->kt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, kt->kt_children)) {
+ VIFM_SET(vifi, kt->kt_grpmems);
+ kt->kt_grpmems &= ~kt->kt_scope;
+ if (kt->kt_grpmems == NULL)
+ continue;
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ }
+}
+
+/*
+ * reset forwarding flag for all mcastgrps on this vifi
+ */
+void delete_lclgrp(vifi, mcastgrp)
+ vifi_t vifi;
+ u_long mcastgrp;
+{
+
+ struct ktable *kt;
+
+ log(LOG_DEBUG, 0, "group %x left at vif %d", mcastgrp, vifi);
+
+ for (kt = kernel_rtable; kt; kt = kt->kt_next)
+ if (kt->kt_mcastgrp == mcastgrp) {
+ VIFM_CLR(vifi, kt->kt_grpmems);
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+
+ /*
+ * If there are no more members of this particular group,
+ * send prune upstream
+ */
+ if (kt->kt_grpmems == NULL && kt->kt_gateway)
+ send_prune(kt);
+ }
+}
+
+/*
+ * Check if the neighbor supports pruning
+ */
+int pruning_neighbor(vifi, addr)
+ vifi_t vifi;
+ u_long addr;
+{
+ struct listaddr *u;
+
+ for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
+ if ((u->al_addr == addr) && (u->al_pv > 2))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Send a prune message to the upstream router
+ * given by the kt->kt_gateway argument. The origin and
+ * multicast group can be determined from the kt
+ * structure.
+ *
+ * Also, record an entry that a prune was sent for this group
+ */
+void send_prune(kt)
+ struct ktable *kt;
+{
+ struct prunlst *krl;
+ char *p;
+ int i;
+ int datalen;
+ u_long src;
+ u_long dst;
+
+ /* Don't process any prunes if router is not pruning */
+ if (pruning == 0)
+ return;
+
+ /* Don't send a prune to a non-pruning router */
+ if (!pruning_neighbor(kt->kt_parent, kt->kt_gateway))
+ return;
+
+ /*
+ * sends a prune message to the router upstream.
+ */
+ src = uvifs[kt->kt_parent].uv_lcl_addr;
+ dst = kt->kt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ /*
+ * determine prune lifetime
+ */
+ kt->kt_prsent_timer = kt->kt_timer;
+ for (krl = kt->kt_rlist; krl; krl = krl->rl_next)
+ if (krl->rl_timer < kt->kt_prsent_timer)
+ kt->kt_prsent_timer = krl->rl_timer;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_mcastgrp))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_prsent_timer))[i];
+ datalen += 12;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
+ htonl(MROUTED_LEVEL), datalen);
+
+ /* log(LOG_DEBUG, 0, "send prune for src:%x, grp:%x up to %x",
+ kt->kt_origin, kt->kt_mcastgrp, kt->kt_gateway);*/
+}
+
+/*
+ * 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_long src;
+ u_long dst;
+ char *p;
+ int datalen;
+{
+ u_long prun_src;
+ u_long prun_dst;
+ u_long prun_tmr;
+ vifi_t vifi;
+ int i;
+ int stop_sending;
+ struct ktable *kt;
+ struct prunlst *pr_recv;
+ struct prunlst *krl;
+ 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;
+ }
+
+ if (datalen < 0 || datalen > 12)
+ {
+ log(LOG_WARNING, 0,
+ "received non-decipherable prune report 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_dst)[i] = *p++;
+ for (i = 0; i< 4; i++)
+ ((char *)&prun_tmr)[i] = *p++;
+
+ kt = find_src_grp(prun_src, prun_dst);
+
+ if (kt == NULL)
+ {
+ log(LOG_WARNING, 0, "prune message received incorrectly");
+ return;
+ }
+
+ if (!VIFM_ISSET(vifi, kt->kt_children))
+ {
+ log(LOG_INFO, 0,
+ "ignoring prune report from non-child %s", inet_fmt(src, s1));
+ return;
+ }
+ if (VIFM_ISSET(vifi, kt->kt_scope)) {
+ log(LOG_INFO, 0,
+ "ignoring prune report from %s on scoped vif %d",
+ inet_fmt(src, s1), vifi);
+ return;
+ }
+ /* check if prune has been received from this source */
+ if (!no_entry_exists(src, kt))
+ {
+ log(LOG_INFO, 0, "duplicate prune from %s", inet_fmt(src, s1));
+ return;
+ }
+
+ log(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s) tmr %d",
+ inet_fmt(src, s1), vifi,
+ inet_fmt(prun_src, s2), inet_fmt(prun_dst, s3), prun_tmr);
+
+ /* allocate space for the prune structure */
+ pr_recv = (struct prunlst *)(malloc(sizeof(struct prunlst)));
+
+ if (pr_recv == NULL)
+ log(LOG_ERR, 0, "pr_recv: ran out of memory");
+
+ pr_recv->rl_vifi = vifi;
+ pr_recv->rl_router = src;
+ pr_recv->rl_timer = prun_tmr;
+
+ /*
+ * add this prune message to the list of prunes received
+ * for this src group pair
+ */
+ pr_recv->rl_next = kt->kt_rlist;
+ kt->kt_rlist = pr_recv;
+
+ kt->kt_prun_count++;
+ kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ if (kt->kt_timer < prun_tmr)
+ kt->kt_timer = prun_tmr;
+
+ /*
+ * check if any more packets need to be sent on the
+ * vif which sent this message
+ */
+ for (vr = uvifs[vifi].uv_neighbors, stop_sending = 1;
+ vr; vr = vr->al_next)
+ if (no_entry_exists(vr->al_addr, kt)) {
+ stop_sending = 0;
+ break;
+ }
+
+ if (stop_sending && !grplst_mem(vifi, prun_dst)) {
+ VIFM_CLR(vifi, kt->kt_grpmems);
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ }
+
+ /*
+ * 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(kt->kt_grpmems == NULL && kt->kt_gateway) {
+ log(LOG_DEBUG, 0, "snt prun up %d %d", kt->kt_prun_count, rtr_cnt(kt));
+ send_prune(kt);
+ }
+}
+
+/*
+ * Returns 1 if router vr is not present in the prunlist of kt
+ */
+int no_entry_exists(vr, kt)
+ u_long vr;
+ struct ktable *kt;
+{
+ struct prunlst *krl;
+
+ for (krl = kt->kt_rlist; krl; krl = krl->rl_next)
+ if (krl->rl_router == vr)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Finds the entry for the source group pair in the table
+ */
+struct ktable *find_src_grp(src, grp)
+ u_long src;
+ u_long grp;
+{
+ struct ktable *kt;
+
+ for (kt = kernel_rtable; kt; kt = kt->kt_next)
+ if ((kt->kt_origin == (src & kt->kt_originmask)) &&
+ (kt->kt_mcastgrp == grp))
+ return kt;
+
+ return NULL;
+}
+
+/*
+ * scans through the neighbor list of this router and then
+ * determines the total no. of child routers present
+ */
+int rtr_cnt(kt)
+ struct ktable *kt;
+{
+ int ri;
+ int rcount = 0;
+ struct listaddr *u;
+
+ for (ri = 0; ri < numvifs; ri++)
+ if (VIFM_ISSET(ri, kt->kt_children))
+ for(u = uvifs[ri].uv_neighbors; u; u = u->al_next)
+ rcount++;
+
+ return rcount;
+}
+
+/*
+ * 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_long mcastgrp;
+{
+ struct ktable *kt;
+
+ for (kt = kernel_rtable; kt; kt = kt->kt_next)
+ if (kt->kt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, kt->kt_children))
+ if (kt->kt_prsent_timer) {
+ VIFM_SET(vifi, kt->kt_grpmems);
+ /*
+ * If the vif that was joined was a scoped vif,
+ * ignore it ; don't graft back
+ */
+ kt->kt_grpmems &= ~kt->kt_scope;
+ if (kt->kt_grpmems == NULL)
+ continue;
+
+ /* set the flag for graft retransmission */
+ kt->kt_grftsnt = 1;
+
+ /* send graft upwards */
+ send_graft(kt);
+
+ /* reset the prune timer and update cache timer*/
+ kt->kt_prsent_timer = 0;
+ kt->kt_timer = max_prune_lifetime;
+
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ }
+}
+
+/* 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 just ignore the message
+ * [this may not be the right thing to do. but lets see what
+ * happens for the time being and then we might decide to do
+ * a modification to the code depending on the type of behaviour
+ * that we see in this]
+ */
+void accept_graft(src, dst, p, datalen)
+ u_long src;
+ u_long dst;
+ char *p;
+ int datalen;
+{
+ vifi_t vifi;
+ u_long prun_src;
+ u_long prun_dst;
+ struct ktable *kt;
+ int i;
+ struct prunlst *krl;
+ struct prunlst *prev_krl;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring graft report from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (datalen < 0 || datalen > 8) {
+ log(LOG_WARNING, 0,
+ "received non-decipherable graft report 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_dst)[i] = *p++;
+
+ log(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)",
+ inet_fmt(src, s1), vifi,
+ inet_fmt(prun_src, s2), inet_fmt(prun_dst, s3));
+
+ kt = find_src_grp(prun_src, prun_dst);
+ if (kt == NULL) {
+ log(LOG_DEBUG, 0, "incorrect graft received from %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (VIFM_ISSET(vifi, kt->kt_scope)) {
+ log(LOG_INFO, 0,
+ "incorrect graft received from %s on scoped vif %d",
+ inet_fmt(src, s1), vifi);
+ return;
+ }
+ /* remove prune entry from the list
+ * allow forwarding on that vif, make change in the kernel
+ */
+ for (prev_krl = (struct prunlst *)&kt->kt_rlist;
+ krl = prev_krl->rl_next;
+ prev_krl = krl)
+ if ((krl->rl_vifi) == vifi && (krl->rl_router == src)) {
+ prev_krl->rl_next = krl->rl_next;
+ free((char *)krl);
+ krl = prev_krl;
+
+ kt->kt_prun_count--;
+ VIFM_SET(vifi, kt->kt_grpmems);
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ break;
+ }
+
+ /* send ack downstream */
+ send_graft_ack(kt, src);
+ kt->kt_timer = max_prune_lifetime;
+
+ if (kt->kt_prsent_timer) {
+ /* set the flag for graft retransmission */
+ kt->kt_grftsnt = 1;
+
+ /* send graft upwards */
+ send_graft(kt);
+
+ /* reset the prune sent timer */
+ kt->kt_prsent_timer = 0;
+ }
+}
+
+/*
+ * Send an ack that a graft was received
+ */
+void send_graft_ack(kt, to)
+ struct ktable *kt;
+ u_long to;
+{
+ register char *p;
+ register int i;
+ int datalen;
+ u_long src;
+ u_long dst;
+
+ src = uvifs[kt->kt_parent].uv_lcl_addr;
+ dst = to;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_mcastgrp))[i];
+ datalen += 8;
+
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
+ htonl(MROUTED_LEVEL), datalen);
+
+ log(LOG_DEBUG, 0, "send graft ack for src:%x, grp:%x to %x",
+ kt->kt_origin, kt->kt_mcastgrp, dst);
+}
+
+/*
+ * 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.
+ */
+void send_graft(kt)
+ struct ktable *kt;
+{
+ register char *p;
+ register int i;
+ int datalen;
+ u_long src;
+ u_long dst;
+
+ src = uvifs[kt->kt_parent].uv_lcl_addr;
+ dst = kt->kt_gateway;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_origin))[i];
+ for (i = 0; i < 4; i++)
+ *p++ = ((char *)&(kt->kt_mcastgrp))[i];
+ datalen += 8;
+
+ if (datalen != 0) {
+ send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
+ htonl(MROUTED_LEVEL), datalen);
+ }
+ log(LOG_DEBUG, 0, "send graft for src:%x, grp:%x up to %x",
+ kt->kt_origin, kt->kt_mcastgrp, kt->kt_gateway);
+}
+
+/*
+ * 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_long src;
+ u_long dst;
+ char *p;
+ int datalen;
+{
+ vifi_t vifi;
+ u_long grft_src;
+ u_long grft_dst;
+ struct ktable *kt;
+ int i;
+
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ log(LOG_INFO, 0,
+ "ignoring graft ack report from non-neighbor %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (datalen < 0 || datalen > 8) {
+ log(LOG_WARNING, 0,
+ "received non-decipherable graft ack report 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_dst)[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_dst, s3));
+
+ kt = find_src_grp(grft_src, grft_dst);
+
+ if (kt == NULL) {
+ log(LOG_WARNING, 0, "received wrong graft ack from %s", inet_fmt(src, s1));
+ return;
+ }
+
+ if (kt->kt_grftsnt)
+ kt->kt_grftsnt = 0;
+}
+
+
+/*
+ * free all prune entries
+ */
+void free_all_prunes()
+{
+ register struct ktable *kt;
+ register struct prunlst *krl;
+
+ while (kernel_rtable != NULL) {
+ kt = kernel_rtable;
+ kernel_rtable = kt->kt_next;
+
+ while (kt->kt_rlist != NULL) {
+ krl = kt->kt_rlist;
+ kt->kt_rlist = krl->rl_next;
+ free((char *)krl);
+ }
+
+ free((char *)kt);
+ kroutes--;
+ }
+}
+
+
+/*
+ * 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 ktable *kt;
+ struct ktable *prev_kt;
+ struct prunlst *krl;
+ struct prunlst *prev_krl;
+
+ log(LOG_DEBUG, 0, "kr:%x pr:%x",
+ kernel_rtable, (struct ktable *)&kernel_rtable);
+
+ for (prev_kt = (struct ktable *)&kernel_rtable;
+ kt = prev_kt->kt_next;
+ prev_kt = kt) {
+ /* advance the timer for the kernel entry */
+ kt->kt_timer -= ROUTE_MAX_REPORT_DELAY;
+
+ /* decrement prune timer if need be */
+ if (kt->kt_prsent_timer)
+ kt->kt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
+
+ /* retransmit graft if graft sent flag is still set */
+ if (kt->kt_grftsnt) {
+ register int y;
+ CHK_GS(kt->kt_grftsnt++, y);
+ if (y)
+ send_graft(kt);
+ }
+
+ /* delete the entry only if there are no subordinate
+ routers
+
+ Now, if there are subordinate routers, then, what we
+ have to do is to decrement each and every router's
+ time entry too and decide if we want to forward on
+ that link basically
+ */
+ for (prev_krl = (struct prunlst *)&kt->kt_rlist,
+ krl = prev_krl->rl_next;
+ krl;
+ prev_krl = krl, krl = krl->rl_next) {
+ if ((krl->rl_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
+ log(LOG_DEBUG, 0, "forw again s %x g%x on vif %d",
+ kt->kt_origin, kt->kt_mcastgrp, krl->rl_vifi);
+
+ if (!VIFM_ISSET(krl->rl_vifi, kt->kt_grpmems)) {
+ VIFM_SET(krl->rl_vifi, kt->kt_grpmems);
+ prun_add_ttls(kt);
+ k_add_rg(kt);
+ }
+
+ kt->kt_prun_count--;
+ prev_krl->rl_next = krl->rl_next;
+ free((char *)krl);
+ krl = prev_krl;
+
+ if (krl == NULL)
+ break;
+ }
+ }
+
+ if (kt->kt_timer <= 0) {
+ /*
+ * If there are prune entries still outstanding,
+ * update the cache timer otherwise expire entry.
+ */
+ if (kt->kt_rlist) {
+ kt->kt_timer = CACHE_LIFETIME(cache_lifetime);
+ }
+ else {
+ log(LOG_DEBUG, 0, "age route s %x g %x",
+ kt->kt_origin, kt->kt_mcastgrp);
+
+ k_del_rg(kt);
+ prev_kt->kt_next = kt->kt_next;
+
+ /* free all the prune list entries */
+ krl = kt->kt_rlist;
+ while(krl) {
+ prev_krl = krl;
+ krl = krl->rl_next;
+ free((char *)prev_krl);
+ }
+
+ free((char *)kt);
+ kroutes--;
+ kt = prev_kt;
+ }
+ }
+ }
+}
+
+/*
+ * Print the contents of the routing table on file 'fp'.
+ */
+void dump_cache(fp2)
+ FILE *fp2;
+{
+ register struct ktable *kt;
+ register struct prunlst *krl;
+ register int i;
+ register int count;
+
+ fprintf(fp2,
+ "Multicast Routing Cache Table (%d entries)\n%s", kroutes,
+ " Origin-Subnet Mcast-group CTmr IVif Prcv# Psnt Forwvifs\n");
+
+ for (kt = kernel_rtable, count = 0; kt != NULL; kt = kt->kt_next) {
+
+ fprintf(fp2, " %-15s %-15s",
+ inet_fmts(kt->kt_origin, kt->kt_originmask, s1),
+ inet_fmt(kt->kt_mcastgrp, s2));
+
+ if (VIFM_ISSET(kt->kt_parent, kt->kt_scope)) {
+ fprintf(fp2, " %5u %2ub %3u %c ",
+ kt->kt_timer, kt->kt_parent, kt->kt_prun_count,
+ kt->kt_prsent_timer ? 'P' : ' ');
+ fprintf(fp2, "\n");
+ continue;
+ }
+ else
+ fprintf(fp2, " %5u %2u %3u %c ",
+ kt->kt_timer, kt->kt_parent, kt->kt_prun_count,
+ kt->kt_prsent_timer ? 'P' : ' ');
+
+ for (i = 0; i < numvifs; ++i) {
+ if (VIFM_ISSET(i, kt->kt_grpmems))
+ fprintf(fp2, " %u ", i);
+ else if (VIFM_ISSET(i, kt->kt_children) &&
+ !VIFM_ISSET(i, kt->kt_leaves) &&
+ VIFM_ISSET(i, kt->kt_scope))
+ fprintf(fp2, " %u%c", i, 'b');
+ else if (VIFM_ISSET(i, kt->kt_children) &&
+ !VIFM_ISSET(i, kt->kt_leaves))
+ fprintf(fp2, " %u%c", i, 'p');
+ }
+ fprintf(fp2, "\n");
+ count++;
+ }
+}
+
+
+/*
+ * Checks if there are any routers that can understand traceroute
+ * downstream
+ */
+int can_forward(vifi)
+ vifi_t vifi;
+{
+ struct listaddr *u;
+
+ for (u = uvifs[vifi].uv_neighbors; u; u = u->al_next)
+ if (((u->al_pv > 2) && (u->al_mv > 2)) ||
+ (u->al_pv > 3))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * Traceroute function which returns traceroute replies to the requesting
+ * router. Also forwards the request to downstream routers.
+ */
+void mtrace(src, dst, group, data, no, datalen)
+ u_long src;
+ u_long dst;
+ u_long group;
+ char *data;
+ u_char no;
+ int datalen;
+{
+ u_char type;
+ struct rtentry *rt;
+ struct tr_query *qry;
+ struct tr_resp *resp;
+ struct uvif *v;
+ int vifi;
+ char *p;
+ struct ktable *kt;
+ int rcount;
+
+ struct timeval tp;
+ struct timezone tzp;
+ struct sioc_vif_req v_req;
+ struct sioc_sg_req sg_req;
+
+ /* timestamp the request/response */
+ gettimeofday(&tp, &tzp);
+
+ /*
+ * Check if it is a query or a response
+ */
+ if (datalen == QLEN) {
+ type = QUERY;
+ printf("Traceroute query rcvd\n");
+ }
+ else if ((datalen - QLEN)%RLEN == 0) {
+ type = RESP;
+ printf("Traceroute response rcvd\n");
+ }
+ else {
+ printf("Non decipherable trace request %s", inet_fmt(src, s1));
+ return;
+ }
+
+ qry = (struct tr_query *)data;
+
+ /*
+ * if it is a multicast packet with all reports filled, drop it
+ */
+ if ((rcount = (datalen - QLEN)/RLEN) == no) {
+ printf("multicast packet with reports filled in\n");
+ return;
+ }
+
+ printf("s: %s g: %s d: %s ", inet_fmt(qry->tr_src, s1),
+ inet_fmt(group, s2), inet_fmt(qry->tr_dst, s3));
+ printf("rttl: %d rd: %s\n", qry->tr_rttl, inet_fmt(qry->tr_raddr, s1));
+ printf("rcount:%d\n", rcount);
+
+ /* determine the routing table entry for this traceroute */
+ rt = determine_route(qry->tr_src);
+
+ /*
+ * 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) {
+ printf("Mcast traceroute: no route entry %s\n",
+ inet_fmt(qry->tr_src, s1));
+ if (IN_MULTICAST(ntohl(dst)))
+ return;
+ }
+ for (v = uvifs, vifi = 0; vifi < numvifs; ++vifi, ++v)
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ ((qry->tr_dst & v->uv_subnetmask) == v->uv_subnet))
+ break;
+
+ if (vifi == numvifs) {
+ printf("Destination %s not an interface\n",
+ inet_fmt(qry->tr_dst, s1));
+ return;
+ }
+ if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
+ printf("Destination %s not on forwarding tree for src %s\n",
+ inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
+ return;
+ }
+ }
+ else {
+ /*
+ * determine which interface the packet came in on
+ */
+ if ((vifi = find_vif(src, dst)) == NO_VIF) {
+ printf("Wrong interface for packet\n");
+ return;
+ }
+ }
+
+ printf("Sending traceroute response\n");
+
+ /* copy the packet to the sending buffer */
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+
+ bcopy(data, p, datalen);
+
+ p += datalen;
+
+ /*
+ * fill in initial response fields
+ */
+ resp = (struct tr_resp *)p;
+ resp->tr_qarr = ((tp.tv_sec & 0xffff) << 16) +
+ ((tp.tv_usec >> 4) & 0xffff);
+
+ resp->tr_vifin = 0; /* default values */
+ resp->tr_pktcnt = 0; /* default values */
+ resp->tr_rproto = PROTO_DVMRP;
+ resp->tr_smask = 0;
+ 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
+ */
+ kt = find_src_grp(qry->tr_src, group);
+
+ if (kt != NULL) {
+ 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.count;
+
+ if (VIFM_ISSET(vifi, kt->kt_scope))
+ resp->tr_rflags = TR_SCOPED;
+ else if (kt->kt_prsent_timer)
+ resp->tr_rflags = TR_PRUNED;
+ }
+
+ /*
+ * if no rte exists, set NO_RTE error
+ */
+ if (rt == NULL) {
+ src = dst; /* the dst address of resp. pkt */
+ resp->tr_inaddr = NULL;
+ resp->tr_rflags = TR_NO_RTE;
+ resp->tr_rmtaddr = NULL;
+ }
+ 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)) {
+ printf("Destination %s not on forwarding tree for src %s\n",
+ inet_fmt(qry->tr_dst, s1), inet_fmt(qry->tr_src, s2));
+ resp->tr_rflags = TR_WRONG_IF;
+ }
+ }
+
+ /*
+ * if metric is 1 or no. of reports is 1, send response to requestor
+ * else send to upstream router.
+ */
+ printf("rcount:%d, no:%d\n", rcount, no);
+
+ if ((rcount + 1 == no) || (rt->rt_metric == 1))
+ dst = qry->tr_raddr;
+ else
+ dst = rt->rt_gateway;
+
+ if (IN_MULTICAST(ntohl(dst))) {
+ k_set_ttl(qry->tr_rttl);
+ send_igmp(src, dst,
+ IGMP_MTRACE_RESP, no, group,
+ datalen + RLEN);
+ k_set_ttl(1);
+ }
+ else
+ send_igmp(src, dst,
+ IGMP_MTRACE, no, group,
+ datalen + RLEN);
+ return;
+}
diff --git a/usr.sbin/mrouted/prune.h b/usr.sbin/mrouted/prune.h
new file mode 100644
index 0000000..3cce25e
--- /dev/null
+++ b/usr.sbin/mrouted/prune.h
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: prune.h,v 1.3 1994/08/24 23:54:40 thyagara Exp $
+ */
+
+/*
+ * Macro for copying the user-level cache table to the kernel
+ * level table variable passed on by the setsock option
+ */
+
+#define COPY_TABLES(from, to) { \
+ register u_int _i; \
+ (to).mfcc_origin.s_addr = (from)->kt_origin; \
+ (to).mfcc_mcastgrp.s_addr = (from)->kt_mcastgrp; \
+ (to).mfcc_originmask.s_addr = (from)->kt_originmask; \
+ (to).mfcc_parent = (from)->kt_parent; \
+ for (_i = 0; _i < numvifs; _i++) \
+ (to).mfcc_ttls[_i] = (from)->kt_ttls[_i]; \
+};
+
+
+/*
+ * User level Kernel Cache Table structure
+ *
+ * A copy of the kernel table is kept at the user level. Modifications are
+ * made to this table and then passed on to the kernel. A timeout value is
+ * an extra field in the user level table.
+ *
+ */
+struct ktable
+{
+ struct ktable *kt_next; /* pointer to the next entry */
+ u_long kt_origin; /* subnet origin of multicasts */
+ u_long kt_mcastgrp; /* multicast group associated */
+ u_long kt_originmask; /* subnet mask for origin */
+ vifi_t kt_parent; /* incoming vif */
+ u_long kt_gateway; /* upstream router */
+ vifbitmap_t kt_children; /* outgoing children vifs */
+ vifbitmap_t kt_leaves; /* subset of outgoing children vifs */
+ vifbitmap_t kt_scope; /* scoped interfaces */
+ u_char kt_ttls[MAXVIFS]; /* ttl vector for forwarding */
+ vifbitmap_t kt_grpmems; /* forw. vifs for src, grp */
+ int kt_timer; /* for timing out entry in cache */
+ struct prunlst *kt_rlist; /* router list nghboring this rter */
+ u_short kt_prun_count; /* count of total no. of prunes */
+ int kt_prsent_timer; /* prune lifetime timer */
+ u_int kt_grftsnt; /* graft sent upstream */
+};
+
+/*
+ * structure to store incoming prunes
+ */
+struct prunlst
+{
+ struct prunlst *rl_next;
+ u_long rl_router;
+ u_long rl_router_subnet;
+ vifi_t rl_vifi;
+ int rl_timer;
+};
+
+struct tr_query {
+ u_long tr_src; /* traceroute source */
+ u_long tr_dst; /* traceroute destination */
+ u_long tr_raddr; /* traceroute response address */
+ struct {
+ u_int ttl : 8; /* traceroute response ttl */
+ u_int qid : 24; /* traceroute query id */
+ } q;
+} tr_query;
+
+#define tr_rttl q.ttl
+#define tr_qid q.qid
+
+struct tr_resp {
+ u_long tr_qarr; /* query arrival time */
+ u_long tr_inaddr; /* incoming interface address */
+ u_long tr_outaddr; /* outgoing interface address */
+ u_long tr_rmtaddr; /* parent address in source tree */
+ u_long tr_vifin; /* input packet count on interface */
+ u_long tr_vifout; /* output packet count on interface */
+ u_long 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 */
+} tr_resp;
+
+/* 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 0x0
+#define TR_WRONG_IF 0x1
+#define TR_PRUNED 0x2
+#define TR_SCOPED 0x4
+#define TR_NO_RTE 0x5
+
+/* fields for tr_rproto (routing protocol) */
+#define PROTO_DVMRP 0x1
+#define PROTO_MOSPF 0x2
+#define PROTO_PIM 0x3
+#define PROTO_CBT 0x4
+
+#define MASK_TO_VAL(x, i) { \
+ (i) = 0; \
+ while ((x) << (i)) \
+ (i)++; \
+ }
+
+#define VAL_TO_MASK(x, i) { \
+ x = ~((1 << (32 - (i))) - 1); \
+ }
diff --git a/usr.sbin/mrouted/route.c b/usr.sbin/mrouted/route.c
new file mode 100644
index 0000000..2debcc7
--- /dev/null
+++ b/usr.sbin/mrouted/route.c
@@ -0,0 +1,1076 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: route.c,v 1.8 1994/08/24 23:54:42 thyagara Exp $
+ */
+
+
+#include "defs.h"
+
+
+/*
+ * Exported variables.
+ */
+int routes_changed; /* 1=>some routes have changed */
+int delay_change_reports; /* 1=>postpone change reports */
+
+
+/*
+ * Private variables.
+ */
+static struct rtentry *routing_table; /* pointer to list of route entries */
+static struct rtentry *rtp; /* pointer to a 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_long 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 = (struct rtentry *)&routing_table;
+}
+
+
+/*
+ * 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_long 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);
+}
+
+
+/*
+ * Search the entire routing table, looking for an entry which conflicts
+ * with the given origin and mask, for example, an entry which has the same
+ * origin under a different mask. If a conflicting entry is found, return
+ * a pointer to the entry preceding it (to facilitate deletion); if no
+ * conflict is found, return NULL.
+ */
+static struct rtentry *find_conflicting_route(origin, mask)
+ register u_long origin, mask;
+{
+ register struct rtentry *r, *prev_r;
+
+ for (prev_r = (struct rtentry *)&routing_table, r = routing_table;
+ r != NULL;
+ prev_r = r, r = r->rt_next ) {
+ if ((origin & r->rt_originmask) == r->rt_origin ||
+ (r->rt_origin & mask) == origin) {
+ return (prev_r);
+ }
+ }
+ return (NULL);
+}
+
+
+/*
+ * 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_long origin, mask;
+{
+ register struct rtentry *r;
+
+ if ((r = (struct rtentry *) malloc(sizeof(struct rtentry)
+ + (3 * 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_long *)(r + 1);
+ r->rt_subordinates = (u_long *)(r->rt_dominants + numvifs);
+ r->rt_leaf_timers = (u_long *)(r->rt_subordinates + numvifs);
+
+ r->rt_next = rtp->rt_next;
+ rtp->rt_next = 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;
+ 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_long origin, mask;
+ int metric;
+ u_long 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)) {
+ /*
+ * 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;
+ }
+
+ /*
+ * If the new origin and mask are inconsistent with an entry
+ * already in the routing table, either ignore this update
+ * (if it came from another router), or delete the conflicting
+ * entry (if the update is for a directly-connected subnet).
+ */
+ if ((prev_r = find_conflicting_route(origin, mask)) != NULL ) {
+ if (src != 0) {
+ log(LOG_INFO, 0,
+ "%s reports a conflicting origin (%s) and mask (%08x)",
+ inet_fmt(src, s1), inet_fmt(origin, s2), ntohl(mask));
+ return;
+ }
+ else {
+ r = prev_r->rt_next;
+ log(LOG_INFO, 0,
+ "deleting route with conflicting origin (%s), mask (%08x)",
+ inet_fmt(r->rt_origin, s1), ntohl(r->rt_originmask));
+
+ if (r->rt_metric != UNREACHABLE) {
+ del_table_entry(r, 0, DEL_ALL_ROUTES);
+ }
+ discard_route(prev_r);
+ if (rtp == r) rtp = prev_r;
+ }
+ }
+
+ /*
+ * OK, create the new routing entry. 'rtp' will be left pointing
+ * to the new entry.
+ */
+ create_route(origin, mask);
+
+ 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 = (struct rtentry *)&routing_table, 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){
+ VIFM_SET(vifi, r->rt_leaves);
+ update_table_entry(r);
+ }
+ else {
+ r->rt_flags |= RTF_LEAF_TIMING;
+ }
+ }
+ }
+ }
+ }
+ else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
+ /*
+ * Time to garbage-collect the route entry.
+ */
+ 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 = (struct rtentry *)&routing_table;
+
+ while (r->rt_next)
+ discard_route(r);
+}
+
+
+/*
+ * Process an incoming neighbor probe message.
+ */
+void accept_probe(src, dst, p, datalen, level)
+ u_long src;
+ u_long dst;
+ char *p;
+ int datalen;
+ u_long 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_long mask;
+ u_long origin;
+ int metric;
+ int pad;
+};
+
+int compare_rts(r1, r2)
+ register struct newrt *r1;
+ register struct newrt *r2;
+{
+ register unsigned long m1 = ntohl(r1->mask);
+ register unsigned long m2 = ntohl(r2->mask);
+ register unsigned long 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_long src, dst, level;
+ register char *p;
+ register int datalen;
+{
+ vifi_t vifi;
+ register int width, i, nrt = 0;
+ int metric;
+ u_long mask;
+ u_long 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;
+ }
+ ((char *)&mask)[0] = 0xff; width = 1;
+ if ((((char *)&mask)[1] = *p++) != 0) width = 2;
+ if ((((char *)&mask)[2] = *p++) != 0) width = 3;
+ if ((((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;
+ ++nrt;
+ } while (!(metric & 0x80));
+ }
+ qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
+ start_route_updates();
+ for (i = 0; i < nrt; ++i)
+ update_route(rt[i].origin, rt[i].mask, (rt[i].metric & 0x7f),
+ 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_long dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ int datalen;
+ int width;
+ u_long mask;
+ u_long src;
+
+ src = uvifs[vifi].uv_lcl_addr;
+
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ 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), 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), 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_long dst;
+{
+ register struct rtentry *r;
+ register char *p;
+ register int i;
+ register int nrt = 0;
+ int datalen;
+ int width;
+ u_long mask;
+ u_long src;
+
+ src = uvifs[vifi].uv_lcl_addr;
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+ mask = 0;
+
+ for (r = start_rt; r != NULL; r = r->rt_next) {
+ /*
+ * 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), 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), datalen);
+ }
+ return (nrt);
+}
+
+/*
+ * send the next chunk of our routing table to all neighbors.
+ */
+int report_next_chunk()
+{
+ register vifi_t vifi;
+ register struct uvif *v;
+ register struct rtentry *r;
+ register struct rtentry *sr;
+ register int i, n = 0;
+ static int start_rt;
+
+ if (nroutes <= 0)
+ return (0);
+
+ /*
+ * find this round's starting route.
+ */
+ for (sr = routing_table, i = start_rt; --i >= 0; ) {
+ sr = sr->rt_next;
+ if (sr == NULL)
+ sr = routing_table;
+ }
+ /*
+ * 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) {
+ n = report_chunk(sr, vifi,
+ (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
+ : dvmrp_group);
+ }
+ }
+ if (debug)
+ printf("update %d starting at %d of %d\n", n, 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;
+
+ fprintf(fp,
+ "Multicast Routing Table (%u %s)\n%s",
+ nroutes, (nroutes == 1) ? "entry" : "entries",
+ " Origin-Subnet From-Gateway Metric In-Vif Out-Vifs\n");
+
+ for (r = routing_table; r != NULL; r = r->rt_next) {
+
+ fprintf(fp, " %-15s %-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, "%7u ",
+ 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_long 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 0000000..2e7aa33
--- /dev/null
+++ b/usr.sbin/mrouted/route.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: route.h,v 1.3 1993/05/30 01:36:38 deering Exp $
+ */
+
+/*
+ * 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 singly-linked list of these structures,
+ * ordered by increasing value of rt_originmask and, secondarily, by
+ * increasing 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_long rt_origin; /* subnet origin of multicasts */
+ u_long 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_long 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_long *rt_dominants; /* per vif dominant gateways */
+ u_long *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 */
+};
+
+#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/vif.c b/usr.sbin/mrouted/vif.c
new file mode 100644
index 0000000..b71a043
--- /dev/null
+++ b/usr.sbin/mrouted/vif.c
@@ -0,0 +1,1138 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: vif.c,v 1.8 1994/08/24 23:54:45 thyagara Exp $
+ */
+
+
+#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. */
+
+/*
+ * Forward declarations.
+ */
+static void start_vif();
+static void stop_vif();
+
+/*
+ * Initialize the virtual interfaces.
+ */
+void init_vifs()
+{
+ vifi_t vifi;
+ struct uvif *v;
+ int enabled_vifs, enabled_phyints;
+
+ 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");
+ config_vifs_from_kernel();
+ 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.
+ */
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
+ if (!(v->uv_flags & VIFF_DISABLED)) {
+ if (!(v->uv_flags & VIFF_DOWN))
+ 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;
+ }
+ }
+ }
+}
+
+
+/*
+ * Start routing on the specified virtual interface.
+ */
+static void start_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ u_long src, dst;
+ int i;
+ char *p;
+ int datalen;
+ struct listaddr *nbr;
+
+ v = &uvifs[vifi];
+ src = v->uv_lcl_addr;
+ dst = (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr : dvmrp_group;
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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,
+ GROUP_EXPIRE_TIME * 10 / ROUTE_MAX_REPORT_DELAY, 0, 0);
+ age_old_hosts();
+ }
+
+ /*
+ * Send a probe via the new vif to look for neighbors.
+ */
+ p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
+ datalen = 0;
+
+ 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(src, dst, IGMP_DVMRP, DVMRP_PROBE,
+ htonl(MROUTED_LEVEL), datalen);
+}
+
+
+/*
+ * Stop routing on the specified virtual interface.
+ */
+static void stop_vif(vifi)
+ vifi_t vifi;
+{
+ struct uvif *v;
+ struct listaddr *a;
+
+ 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);
+
+ /*
+ * 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);
+
+ /*
+ * 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.
+ */
+ 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_long src;
+ register u_long dst;
+{
+ 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))) {
+ 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);
+ }
+ }
+ }
+ return (NO_VIF);
+}
+
+
+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,
+ GROUP_EXPIRE_TIME * 10 / ROUTE_MAX_REPORT_DELAY, 0, 0);
+ }
+ }
+ age_old_hosts();
+}
+
+
+/*
+ * Process an incoming group membership report.
+ */
+void accept_group_report(src, dst, group, r_type)
+ u_long 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_HOST_NEW_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_HOST_NEW_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;
+ 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 leave_group_message( src, dst, group)
+ u_long 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 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) {
+ log(LOG_DEBUG, 0,
+ "[vif.c, _leave_group_message] %d %d \n",
+ g->al_old, g->al_query);
+
+ if (g->al_old)
+ return;
+
+ /** delete old timer set a timer for expiration **/
+ if (g->al_timerid)
+ g->al_timerid = DeleteTimer(g->al_timerid);
+ if (g->al_query)
+ return;
+
+ /** send a group specific querry **/
+ g->al_timer = GROUP_EXPIRE_TIME / 10;
+ send_igmp(v->uv_lcl_addr, g->al_addr,
+ IGMP_HOST_MEMBERSHIP_QUERY,
+ IGMP_MAX_HOST_REPORT_DELAY * 10 / (2*TIMER_INTERVAL),
+ 0, 0);
+ g->al_query = SetQueryTimer(g, vifi, g->al_timer / 3 ,
+ IGMP_MAX_HOST_REPORT_DELAY / 2);
+ 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;
+ int i;
+ register char *p;
+ register int datalen = 0;
+ struct listaddr *nbr;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; vifi++, v++) {
+ if (!(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
+
+ 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), datalen);
+ }
+ }
+}
+
+
+/*
+ * Send a list of all of our neighbors to the requestor, `src'.
+ */
+void accept_neighbor_request(src, dst)
+ u_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long 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;
+ addr.sin_len = sizeof addr;
+ 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_long src, dst;
+{
+ vifi_t vifi;
+ struct uvif *v;
+ u_char *p, *ncount;
+ struct listaddr *la;
+ int datalen;
+ u_long 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;
+ addr.sin_len = sizeof addr;
+ 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;
+ 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_long 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_long 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_long addr;
+ int msgtype;
+ char *p;
+ int datalen;
+ u_long level;
+{
+ register struct uvif *v;
+ register struct listaddr *n;
+ u_long genid;
+ u_long router;
+ int he_hears_me = TRUE;
+
+ v = &uvifs[vifi];
+
+ /*
+ * 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.
+ * Need to reset the prune state of the router if not.
+ */
+ if (msgtype == DVMRP_PROBE) {
+ int i;
+
+ if (datalen < 4) {
+ log(LOG_WARNING, 0,
+ "received truncated probe message from %s",
+ inet_fmt(addr, s1));
+ return;
+ }
+
+ 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",
+ inet_fmt(addr, s1));
+ return;
+ }
+ 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)) {
+ log(LOG_DEBUG, 0,
+ "old:%d new:%dreset neighbor %s",
+ n->al_genid, genid, inet_fmt(addr, s1));
+
+ reset_neighbor_state(vifi, addr);
+ n->al_genid = genid;
+ /* need to do a full route report here */
+ break;
+ }
+
+ /* recurring probe - so no need to do a route report */
+ return FALSE;
+ }
+ break;
+ }
+ }
+
+ /*
+ * 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) {
+ 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;
+
+ n->al_timer = 0;
+ n->al_next = v->uv_neighbors;
+ v->uv_neighbors = n;
+
+ if (!(v->uv_flags & VIFF_TUNNEL) &&
+ ntohl(addr) < ntohl(v->uv_lcl_addr))
+ v->uv_flags &= ~VIFF_QUERIER;
+ }
+
+ 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_long addr;
+
+ for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v ) {
+
+ 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_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;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * 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;
+ struct sioc_vif_req v_req;
+
+ 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: %-15s %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");
+ fprintf(fp, "\n");
+
+ if (v->uv_neighbors != NULL) {
+ fprintf(fp, " peers: %s (%d.%d)\n",
+ inet_fmt(v->uv_neighbors->al_addr, s1),
+ v->uv_neighbors->al_pv, v->uv_neighbors->al_mv);
+ for (a = v->uv_neighbors->al_next; a != NULL; a = a->al_next) {
+ fprintf(fp, " %s (%d.%d)\n",
+ inet_fmt(a->al_addr, s1), a->al_pv, a->al_mv);
+ }
+ }
+
+ 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: %-15s\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, " : %-15s\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;
+
+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);
+}
+
+
+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);
+}
+
+DeleteTimer( id)
+int id;
+{
+ timer_clearTimer(id);
+ return 0;
+}
+
+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 * 10 / TIMER_INTERVAL, 0, 0);
+ cbk->g->al_query = 0;
+ free(cbk);
+}
+
+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 0000000..3cfa2e5
--- /dev/null
+++ b/usr.sbin/mrouted/vif.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ *
+ *
+ * $Id: vif.h,v 1.6 1994/08/24 23:54:47 thyagara Exp $
+ */
+
+/*
+ * 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_long uv_lcl_addr; /* local address of this vif */
+ u_long uv_rmt_addr; /* remote end-point addr (tunnels only) */
+ u_long uv_subnet; /* subnet number (phyints only) */
+ u_long uv_subnetmask; /* subnet mask (phyints only) */
+ u_long 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 */
+};
+
+#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 */
+
+struct vif_acl {
+ struct vif_acl *acl_next; /* next acl member */
+ u_long acl_addr; /* Group address */
+ u_long acl_mask; /* Group addr. mask */
+};
+
+struct listaddr {
+ struct listaddr *al_next; /* link to next addr, MUST BE FIRST */
+ u_long al_addr; /* local group or neighbor address */
+ u_long al_timer; /* for timing out group or neighbor */
+ u_long 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 */
+};
+
+
+#define NO_VIF ((vifi_t)MAXVIFS) /* An invalid vif index */
diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile
new file mode 100644
index 0000000..2e58af2
--- /dev/null
+++ b/usr.sbin/mtree/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= mtree
+SRCS= compare.c crc.c create.c misc.c mtree.c spec.c verify.c
+MAN8= mtree.8
+.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 0000000..c8740fc
--- /dev/null
+++ b/usr.sbin/mtree/compare.c
@@ -0,0 +1,271 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)compare.c 8.1 (Berkeley) 6/6/93";
+#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 - (int)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 (%lu, %lu",
+ 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 (%lu, %lu",
+ 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 0000000..8529986
--- /dev/null
+++ b/usr.sbin/mtree/create.c
@@ -0,0 +1,333 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)create.c 8.1 (Berkeley) 6/6/93";
+#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 long int crc_total;
+extern int ftsoptions;
+extern int dflag, iflag, nflag, 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, int *, const char *, ...));
+static int statd __P((FTS *, FTSENT *, uid_t *, gid_t *, mode_t *));
+static void statf __P((int, FTSENT *));
+
+void
+cwalk()
+{
+ register FTS *t;
+ register FTSENT *p;
+ time_t clock;
+ char *argv[2], host[MAXHOSTNAMELEN];
+ int indent = 0;
+
+ (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))) {
+ if (iflag)
+ indent = p->fts_level * 4;
+ switch(p->fts_info) {
+ case FTS_D:
+ if (!dflag)
+ (void)printf("\n");
+ if (!nflag)
+ (void)printf("# %s\n", p->fts_path);
+ statd(t, p, &uid, &gid, &mode);
+ statf(indent, p);
+ break;
+ case FTS_DP:
+ if (!nflag && (p->fts_level > 0))
+ (void)printf("%*s# %s\n", indent, "", p->fts_path);
+ (void)printf("%*s..\n", indent, "");
+ if (!dflag)
+ (void)printf("\n");
+ 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(indent, 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(indent, p)
+ int indent;
+ FTSENT *p;
+{
+ struct group *gr;
+ struct passwd *pw;
+ u_long len, val;
+ int fd, offset;
+
+ if (iflag || S_ISDIR(p->fts_statp->st_mode))
+ offset = printf("%*s%s", indent, "", p->fts_name);
+ else
+ offset = printf("%*s %s", indent, "", p->fts_name);
+
+ if (offset > (INDENTNAMELEN + indent))
+ offset = MAXLINELEN;
+ else
+ offset += printf("%*s", (INDENTNAMELEN + indent) - offset, "");
+
+ if (!S_ISREG(p->fts_statp->st_mode) && !dflag)
+ output(indent, &offset, "type=%s", inotype(p->fts_statp->st_mode));
+ if (p->fts_statp->st_uid != uid) {
+ if (keys & F_UNAME) {
+ if ((pw = getpwuid(p->fts_statp->st_uid)) != NULL) {
+ output(indent, &offset, "uname=%s", pw->pw_name);
+ } else {
+ err("could not get uname for uid=%u",
+ p->fts_statp->st_uid);
+ }
+ }
+ if (keys & F_UID)
+ output(indent, &offset, "uid=%u", p->fts_statp->st_uid);
+ }
+ if (p->fts_statp->st_gid != gid) {
+ if (keys & F_GNAME) {
+ if ((gr = getgrgid(p->fts_statp->st_gid)) != NULL) {
+ output(indent, &offset, "gname=%s", gr->gr_name);
+ } else {
+ err("could not get gname for gid=%u",
+ p->fts_statp->st_gid);
+ }
+ }
+ if (keys & F_GID)
+ output(indent, &offset, "gid=%u", p->fts_statp->st_gid);
+ }
+ if (keys & F_MODE && (p->fts_statp->st_mode & MBITS) != mode)
+ output(indent, &offset, "mode=%#o", p->fts_statp->st_mode & MBITS);
+ if (keys & F_NLINK && p->fts_statp->st_nlink != 1)
+ output(indent, &offset, "nlink=%u", p->fts_statp->st_nlink);
+ if (keys & F_SIZE)
+ output(indent, &offset, "size=%qd", p->fts_statp->st_size);
+ if (keys & F_TIME)
+ output(indent, &offset, "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, &offset, "cksum=%lu", val);
+ }
+ if (keys & F_SLINK &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE))
+ output(indent, &offset, "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 = *pgid;
+ uid_t saveuid = *puid;
+ mode_t savemode = *pmode;
+ u_short maxgid, maxuid, maxmode, g[MAXGID], u[MAXUID], m[MAXMODE];
+ static int first = 1;
+
+ 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) {
+ if (!dflag || (dflag && S_ISDIR(p->fts_statp->st_mode))) {
+ 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];
+ }
+ }
+ }
+ /*
+ * If the /set record is the same as the last one we do not need to output
+ * a new one. So first we check to see if anything changed. Note that we
+ * always output a /set record for the first directory.
+ */
+ if ((((keys & F_UNAME) | (keys & F_UID)) && (*puid != saveuid)) ||
+ (((keys & F_GNAME) | (keys & F_GID)) && (*pgid != savegid)) ||
+ ((keys & F_MODE) && (*pmode != savemode)) || (first)) {
+ first = 0;
+ if (dflag)
+ (void)printf("/set type=dir");
+ else
+ (void)printf("/set type=file");
+ if (keys & F_UNAME)
+ if ((pw = getpwuid(saveuid)) != NULL)
+ (void)printf(" uname=%s", pw->pw_name);
+ else
+ err("could not get uname for uid=%u", saveuid);
+ if (keys & F_UID)
+ (void)printf(" uid=%lu", saveuid);
+ if (keys & F_GNAME)
+ if ((gr = getgrgid(savegid)) != NULL)
+ (void)printf(" gname=%s", gr->gr_name);
+ else
+ err("could not get gname for gid=%u", savegid);
+ if (keys & F_GID)
+ (void)printf(" gid=%lu", savegid);
+ 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 indent, int *offset, const char *fmt, ...)
+#else
+output(indent, offset, fmt, va_alist)
+ int indent;
+ 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 + indent, "");
+ *offset = INDENTNAMELEN + indent;
+ }
+ *offset += printf(" %s", buf) + 1;
+}
diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/mtree/extern.h
new file mode 100644
index 0000000..72c5dbc
--- /dev/null
+++ b/usr.sbin/mtree/extern.h
@@ -0,0 +1,44 @@
+/*-
+ * 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 0000000..ff97084
--- /dev/null
+++ b/usr.sbin/mtree/misc.c
@@ -0,0 +1,126 @@
+/*-
+ * 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},
+ {"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)fflush(NULL);
+ (void)fprintf(stderr, "\nmtree: ");
+ (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 0000000..e8a4cb2
--- /dev/null
+++ b/usr.sbin/mtree/mtree.8
@@ -0,0 +1,263 @@
+.\" 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 cdeinrux
+.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 specifications, 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 i
+Indents the output 4 spaces each time a directory level is descended when
+create a specification with the
+.Fl c
+option.
+This does not effect either the /set statements or the comment before each
+directory.
+It does however effect the comment before the close of each directory.
+.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 n
+Do not emit pathname comments when creating a specification. Normally
+a comment is emitted before each directory and before the close of that
+directory when using the
+.Fl c
+option.
+.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 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 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 link
+The file the symbolic link is expected to reference.
+.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 mode ,
+.Cm nlink ,
+.Cm size ,
+.Cm link ,
+.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 0000000..9f5aad6
--- /dev/null
+++ b/usr.sbin/mtree/mtree.c
@@ -0,0 +1,152 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)mtree.c 8.1 (Berkeley) 6/6/93";
+#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 long int crc_total;
+
+int ftsoptions = FTS_PHYSICAL;
+int cflag, dflag, eflag, iflag, nflag, 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:iK:k:np: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 'i':
+ iflag = 1;
+ 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 'n':
+ nflag = 1;
+ 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 [-cdeinrux] [-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 0000000..5583127
--- /dev/null
+++ b/usr.sbin/mtree/mtree.h
@@ -0,0 +1,88 @@
+/*-
+ * 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_SIZE 0x0100 /* size */
+#define F_SLINK 0x0200 /* link count */
+#define F_TIME 0x0400 /* modification time */
+#define F_TYPE 0x0800 /* file type */
+#define F_UID 0x1000 /* uid */
+#define F_UNAME 0x2000 /* user name */
+#define F_VISIT 0x4000 /* 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 0000000..a2c5171
--- /dev/null
+++ b/usr.sbin/mtree/spec.c
@@ -0,0 +1,280 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)spec.c 8.1 (Berkeley) 6/6/93";
+#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];
+
+ centry = last = 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 = NULL;
+ 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 = strtoul(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 0000000..4abf0fb
--- /dev/null
+++ b/usr.sbin/mtree/verify.c
@@ -0,0 +1,203 @@
+/*-
+ * 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[] = "@(#)verify.c 8.1 (Berkeley) 6/6/93";
+#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 long int crc_total;
+extern int 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->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 0000000..c337c36
--- /dev/null
+++ b/usr.sbin/named/Makefile
@@ -0,0 +1,80 @@
+#
+# @(#)Makefile 5.8 (Berkeley) 7/28/90
+#
+
+## ++Copyright++ 1985, 1989
+## -
+## Copyright (c) 1985, 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.
+## -
+## 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--
+
+PROG= named
+MAN8= named.8
+LDADD= -lutil
+SRCS= db_dump.c db_load.c db_lookup.c db_reload.c db_save.c db_update.c \
+ db_secure.c db_glue.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 ns_validate.c ns_ncache.c \
+ storage.c dmalloc.c tree.c
+OBJS+= version.o
+CLEANFILES+=version.c version.o
+SUBDIR= tools xfer
+
+VER = LOCAL-`date +%y%m%d.%H%M%S`
+
+version.c: ${.CURDIR}/Version.c ${.CURDIR}/Makefile ${SRCS}
+ (u=$${USER-root} d=`pwd |sed -e 's|/obj/|/src/|'` \
+ h=`hostname` t=`date`; \
+ sed -e "s|%WHEN%|$${t}|" -e "s|%VERSION%|"${VER}"|" \
+ -e "s|%WHOANDWHERE%|$${u}@$${h}:$${d}|" \
+ < ${.CURDIR}/Version.c > version.c)
+
+.include <bsd.prog.mk>
+
diff --git a/usr.sbin/named/Version.c b/usr.sbin/named/Version.c
new file mode 100644
index 0000000..7cbce28
--- /dev/null
+++ b/usr.sbin/named/Version.c
@@ -0,0 +1,88 @@
+/*
+ * @(#)Version.c 4.9 (Berkeley) 7/21/90
+ * $Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $
+ */
+
+#ifndef lint
+char sccsid[] = "@(#)named %VERSION% %WHEN% %WHOANDWHERE%";
+char rcsid[] = "$Id: Version.c,v 4.9.1.3 1994/06/01 21:09:39 vixie Exp $";
+#endif /* not lint */
+
+char Version[] = "named %VERSION% %WHEN%\n\t%WHOANDWHERE%";
+
+#ifdef COMMENT
+
+SCCS/s.Version.c:
+
+D 4.8.3 90/06/27 17:05:21 bloom 37 35 00031/00028/00079
+Version distributed with 4.3 Reno tape (June 1990)
+
+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 4.14 (Berkeley) 2/28/88
+db.h
+ db.h 4.13 (Berkeley) 2/17/88
+db_dump.c
+ db_dump.c 4.20 (Berkeley) 2/17/88
+db_load.c
+ db_load.c 4.26 (Berkeley) 2/28/88
+db_lookup.c
+ db_lookup.c 4.14 (Berkeley) 2/17/88
+db_reload.c
+ db_reload.c 4.15 (Berkeley) 2/28/88
+db_save.c
+ db_save.c 4.13 (Berkeley) 2/17/88
+db_update.c
+ db_update.c 4.16 (Berkeley) 2/28/88
+ns_forw.c
+ ns_forw.c 4.26 (Berkeley) 3/28/88
+ns_init.c
+ ns_init.c 4.23 (Berkeley) 2/28/88
+ns_main.c
+ Copyright (c) 1986 Regents of the University of California.\n\
+ ns_main.c 4.30 (Berkeley) 3/7/88
+ns_maint.c
+ ns_maint.c 4.23 (Berkeley) 2/28/88
+ns_req.c
+ ns_req.c 4.32 (Berkeley) 3/31/88
+ns_resp.c
+ ns_resp.c 4.50 (Berkeley) 4/7/88
+ns_sort.c
+ ns_sort.c 4.3 (Berkeley) 2/17/88
+ns_stats.c
+ ns_stats.c 4.3 (Berkeley) 2/17/88
+newvers.sh
+ newvers.sh 4.4 (Berkeley) 3/28/88
+
+#endif /* COMMENT */
diff --git a/usr.sbin/named/db_defs.h b/usr.sbin/named/db_defs.h
new file mode 100644
index 0000000..db9b32c
--- /dev/null
+++ b/usr.sbin/named/db_defs.h
@@ -0,0 +1,172 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_defs.h,v 1.11 1994/07/22 08:42:39 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1985, 1990
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Global definitions 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
+
+#define DB_ROOT_TIMBUF 3600
+#define TIMBUF 300
+
+/*
+ * Hash table structures.
+ */
+struct databuf {
+ struct databuf *d_next; /* linked list */
+ u_int32_t d_ttl; /* time to live */
+ /* if d_zone == DB_Z_CACHE, then
+ * d_ttl is actually the time when
+ * the record will expire.
+ * otherwise (for authoritative
+ * primary and secondary zones),
+ * d_ttl is the time to live.
+ */
+ unsigned d_flags :7; /* see below */
+ unsigned d_cred :3; /* DB_C_{??????} */
+ unsigned d_clev :6;
+ int16_t d_zone; /* zone number or 0 for the cache */
+ int16_t d_class; /* class number */
+ int16_t d_type; /* type number */
+ int16_t d_mark; /* place to mark data */
+ int16_t d_size; /* size of data area */
+#ifdef NCACHE
+ int16_t d_rcode; /* rcode added for negative caching */
+#endif
+ int16_t d_rcnt;
+#ifdef STATS
+ struct nameser *d_ns; /* NS from whence this came */
+#endif
+/*XXX*/ u_int32_t d_nstime; /* NS response time, milliseconds */
+ u_char d_data[sizeof(char*)]; /* malloc'd (padded) */
+};
+#define DATASIZE(n) (sizeof(struct databuf) - sizeof(char*) + n)
+
+/*
+ * d_flags definitions
+ */
+#define DB_F_HINT 0x01 /* databuf belongs to fcachetab */
+
+/*
+ * d_cred definitions
+ */
+#define DB_C_ZONE 4 /* authoritative zone - best */
+#define DB_C_AUTH 3 /* authoritative answer */
+#define DB_C_ANSWER 2 /* non-authoritative answer */
+#define DB_C_ADDITIONAL 1 /* additional data */
+#define DB_C_CACHE 0 /* cache - worst */
+
+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 */
+};
+
+#ifdef INVQ
+struct invbuf {
+ struct invbuf *i_next; /* linked list */
+ struct namebuf *i_dname[INVBLKSZ]; /* domain name */
+};
+#endif
+
+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
diff --git a/usr.sbin/named/db_dump.c b/usr.sbin/named/db_dump.c
new file mode 100644
index 0000000..3c9b5a4
--- /dev/null
+++ b/usr.sbin/named/db_dump.c
@@ -0,0 +1,897 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_dump.c 4.33 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: db_dump.c,v 1.1.1.1 1994/09/22 19:46:10 pst Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netiso/iso.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include "named.h"
+
+static int scan_root __P((struct hashbuf *));
+static const char *MkCredStr __P((int));
+
+#ifdef ALLOW_T_UNSPEC
+static void putbyte __P((int, char **));
+#endif
+
+/*
+ * 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.
+ */
+
+void
+doachkpt()
+{
+ FILE *fp;
+ char tmpcheckfile[256];
+
+ /* nowhere to checkpoint cache... */
+ if (cache_file == NULL) {
+ dprintf(3, (ddt, "skipping doachkpt (cache_file == NULL)\n"));
+ return;
+ }
+
+ dprintf(3, (ddt, "doachkpt()\n"));
+
+ (void) sprintf(tmpcheckfile, "%s.chk", cache_file);
+ if ((fp = fopen(tmpcheckfile, "w")) == NULL) {
+ dprintf(3, (ddt,
+ "doachkpt(can't open %s for write)\n", tmpcheckfile));
+ return;
+ }
+
+ (void) gettime(&tt);
+ fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+ fflush(fp);
+ if (ferror(fp)) {
+ dprintf(3, (ddt, "doachkpt(write to checkpoint file failed)\n"));
+ return;
+ }
+
+ if (fcachetab != NULL) {
+ int n = scan_root(hashtab);
+
+ if (n < 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) {
+ dprintf(3, (ddt, "doachkpt(checkpoint failed)\n"));
+ (void) my_fclose(fp);
+ return;
+ }
+ }
+
+ (void) fsync(fileno(fp));
+ if (my_fclose(fp) == EOF) {
+ return;
+ }
+
+ if (rename(tmpcheckfile, cache_file)) {
+ dprintf(3, (ddt, "doachkpt(install %s to %s failed, %d)\n",
+ tmpcheckfile, cache_file, errno));
+ }
+}
+
+/*
+ * 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).
+ */
+
+static int
+scan_root(htp)
+ struct hashbuf *htp;
+{
+ register struct databuf *dp;
+ register struct namebuf *np;
+ struct timeval soon;
+ int roots = 0;
+
+ dprintf(1, (ddt, "scan_root(0x%x)\n", htp));
+
+ /* 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;
+
+ dprintf(1, (ddt, "mark_cache()\n"));
+
+ (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.
+ */
+
+void
+doadump()
+{
+ FILE *fp;
+
+ dprintf(3, (ddt, "doadump()\n"));
+
+ if ((fp = fopen(dumpfile, "w")) == NULL)
+ return;
+ gettime(&tt);
+ fprintf(fp, "; Dumped at %s", ctime(&tt.tv_sec));
+ if (zones && nzones)
+ zt_dump(fp);
+ fputs(
+"; Note: Cr=(auth,answer,addtnl,cache) tag only shown for non-auth RR's\n",
+ fp);
+ fputs(
+"; Note: NT=milliseconds for any A RR which we've used as a nameserver\n",
+ fp);
+ 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) my_fclose(fp);
+}
+
+#ifdef ALLOW_UPDATES
+/* Create a disk database to back up zones
+ */
+void
+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)) {
+ dprintf(1, (ddt, "zonedump(%s)\n", zp->z_source));
+
+ if ((fp = fopen(zp->z_source, "w")) == NULL)
+ return;
+ if (op = strchr(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));
+ zp->z_flags &= ~Z_CHANGED; /* Checkpointed */
+ }
+ (void) my_fclose(fp);
+ if (stat(zp->z_source, &st) == 0)
+ zp->z_ftime = st.st_mtime;
+ } else {
+ dprintf(1, (ddt, "zonedump: no zone to dump\n"));
+ }
+}
+#endif
+
+int
+zt_dump(fp)
+ FILE *fp;
+{
+ register struct zoneinfo *zp;
+
+ fprintf(fp, ";; ++zone table++\n");
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ char *pre, buf[64];
+ u_int cnt;
+
+ fprintf(fp, "; %s (type %d, class %d, source %s)\n",
+ zp->z_origin, zp->z_type, zp->z_class,
+ zp->z_source ? zp->z_source : "Nil");
+ fprintf(fp, ";\ttime=%ld, lastupdate=%ld, serial=%u,\n",
+ zp->z_time, zp->z_lastupdate, zp->z_serial);
+ fprintf(fp, ";\trefresh=%u, retry=%u, expire=%u, minimum=%u\n",
+ zp->z_refresh, zp->z_retry,
+ zp->z_expire, zp->z_minimum);
+ fprintf(fp, ";\tftime=%ld, xaddr=[%s], state=%04x, pid=%d\n",
+ zp->z_ftime, inet_ntoa(zp->z_xaddr),
+ zp->z_flags, zp->z_xferpid);
+ sprintf(buf, ";\tz_addr[%d]: ", zp->z_addrcnt);
+ pre = buf;
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+ fprintf(fp, "%s[%s]", pre, inet_ntoa(zp->z_addr[cnt]));
+ pre = ", ";
+ }
+ if (zp->z_addrcnt)
+ fputc('\n', fp);
+ }
+ fprintf(fp, ";; --zone table--\n");
+}
+
+int
+db_dump(htp, fp, zone, origin)
+ struct hashbuf *htp;
+ FILE *fp;
+ int zone;
+ char *origin;
+{
+ register struct databuf *dp = NULL;
+ register struct namebuf *np;
+ struct namebuf **npp, **nppend;
+ char dname[MAXDNAME];
+ u_int32_t n;
+ u_int32_t addr;
+ int j, i;
+ struct iso_addr isoa;
+ register u_char *cp;
+ u_char *end;
+ char *proto, *sep;
+ int found_data = 0, 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;
+#ifdef NCACHE
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+ fputc(';', fp);
+ } else if (found_data == 0 || found_data == 1) {
+ found_data = 2;
+ }
+#endif /*NCACHE*/
+ if (found_data == 0 || found_data == 2) {
+ 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
+ && (int32_t)(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;
+ sep = "\t;";
+#ifdef NCACHE
+#ifdef RETURNSOA
+ if (dp->d_rcode == NOERROR_NODATA) {
+ fprintf(fp, "NODATA%s-$", sep);
+ goto eoln;
+ }
+#else
+ if (dp->d_rcode == NXDOMAIN ||
+ dp->d_rcode == NOERROR_NODATA) {
+ fprintf(fp, "%s%s-$",
+ (dp->d_rcode == NXDOMAIN)
+ ?"NXDOMAIN" :"NODATA",
+ sep);
+ goto eoln;
+ }
+#endif
+#endif
+ /*
+ * 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, "%sNT=%d",
+ sep, dp->d_nstime);
+ sep = " ";
+ }
+ break;
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ fprintf(fp, "%s.", cp);
+ break;
+
+ case T_NS:
+ cp = (u_char *)dp->d_data;
+ if (cp[0] == '\0')
+ fprintf(fp, ".\t");
+ else
+ fprintf(fp, "%s.", cp);
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ 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, " \"\"");
+ break;
+
+ case T_SOA:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s. (\n", cp);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN)
+ fputs(";", fp);
+#endif
+ 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);
+#if defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN) {
+ fprintf(fp,";%s.;NXDOMAIN%s-$",cp,sep);
+ }
+#endif
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ fprintf(fp,"%lu", n);
+ fprintf(fp," %s.", cp);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ 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("\"", fp);
+ break;
+
+ case T_NSAP:
+ isoa.isoa_len = dp->d_size;
+ if (isoa.isoa_len > sizeof(isoa.isoa_genaddr))
+ isoa.isoa_len = sizeof(isoa.isoa_genaddr);
+ bcopy(dp->d_data, isoa.isoa_genaddr,
+ isoa.isoa_len);
+ (void) fputs(iso_ntoa(&isoa), fp);
+ break;
+
+ case T_UINFO:
+ fprintf(fp, "\"%s\"", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (dp->d_size == INT32SZ) {
+ GETLONG(n, cp);
+ } else {
+ n = -2; /* XXX - hack */
+ }
+ fprintf(fp, "%u", 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);
+ }
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ fprintf(fp, "%s.", cp);
+ cp += strlen((char *)cp) + 1;
+ fprintf(fp, " %s.", 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) {
+ dprintf(1,
+ (ddt,
+ "Dump T_UNSPEC: bad malloc\n"
+ )
+ );
+ syslog(LOG_ERR,
+ "Dump T_UNSPEC: malloc: %m");
+ TmpBuf = "BAD_MALLOC";
+ }
+ if (btoa(cp, dp->d_size, TmpBuf, TmpSize)
+ == CONV_OVERFLOW) {
+ dprintf(1, (ddt,
+ "Dump T_UNSPEC: Output buffer overflow\n"
+ )
+ );
+ syslog(LOG_ERR,
+ "Dump T_UNSPEC: Output buffer overflow\n");
+ TmpBuf = "OVERFLOW";
+ }
+ fprintf(fp, "%s", TmpBuf);
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+ default:
+ fprintf(fp, "%s?d_type=%d?",
+ sep, dp->d_type);
+ sep = " ";
+ }
+ if (dp->d_cred < DB_C_ZONE) {
+ fprintf(fp, "%sCr=%s",
+ sep, MkCredStr(dp->d_cred));
+ sep = " ";
+ } else {
+ fprintf(fp, "%sCl=%d",
+ sep, dp->d_clev);
+ sep = " ";
+ }
+eoln:
+#ifdef STATS
+ if (dp->d_ns) {
+ fprintf(fp, "%s[%s]",
+ sep, inet_ntoa(dp->d_ns->addr));
+ sep = " ";
+ }
+#endif
+ putc('\n', fp);
+ }
+ }
+ }
+ 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);
+}
+
+static const char *
+MkCredStr(cred)
+ int cred;
+{
+ static char badness[20];
+
+ switch (cred) {
+ case DB_C_ZONE: return "zone";
+ case DB_C_AUTH: return "auth";
+ case DB_C_ANSWER: return "answer";
+ case DB_C_ADDITIONAL: return "addtnl";
+ case DB_C_CACHE: return "cache";
+ default: break;
+ }
+ sprintf(badness, "?%d?", cred);
+ return (badness);
+}
+
+#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 int32_t Ceor, Csum, Crot, word, bcount;
+
+#define EN(c) ((int) ((c) + '!'))
+#define DE(c) ((c) - '!')
+#define AddToBuf(bufp, c) **bufp = c; (*bufp)++;
+#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 void
+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;
+ int32_t 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 void
+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 int32_t tmpword = word;
+
+ if (tmpword < 0) {
+ /* Because some don't support unsigned long */
+ tmp = 32;
+ tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ if (tmpword < 0) {
+ tmp = 64;
+ tmpword -= (int32_t)(85 * 85 * 85 * 85 * 32);
+ }
+ AddToBuf(bufp,
+ EN((tmpword / (int32_t)(85 * 85 * 85 * 85)) + tmp));
+ tmpword %= (int32_t)(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
+ */
+static int
+btoa(inbuf, inbuflen, outbuf, outbuflen)
+ char *inbuf;
+ int inbuflen;
+ char *outbuf;
+ int outbuflen;
+{
+ int32_t inc, nb;
+ int32_t 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_func.h b/usr.sbin/named/db_func.h
new file mode 100644
index 0000000..1c7275c
--- /dev/null
+++ b/usr.sbin/named/db_func.h
@@ -0,0 +1,102 @@
+/* db_proc.h - prototypes for functions in db_*.c
+ *
+ * $Id: db_func.h,v 1.8 1994/07/23 23:23:56 vixie Exp $
+ */
+
+/* ++from db_update.c++ */
+extern int db_update __P((char name[],
+ struct databuf *odp,
+ struct databuf *newdp,
+ int flags,
+ struct hashbuf *htp));
+/* --from db_update.c-- */
+
+/* ++from db_reload.c++ */
+extern void db_reload __P((void));
+/* --from db_reload.c-- */
+
+/* ++from db_save.c++ */
+extern struct namebuf *savename __P((char *));
+#ifdef DMALLOC
+extern struct databuf *savedata_tagged __P((char *, int,
+ int, int, u_int32_t,
+ u_char *, int));
+#define savedata(class, type, ttl, data, size) \
+ savedata_tagged(__FILE__, __LINE__, class, type, ttl, data, size)
+#else
+extern struct databuf *savedata __P((int, int, u_int32_t,
+ u_char *, int));
+#endif
+extern struct hashbuf *savehash __P((struct hashbuf *));
+/* --from db_save.c-- */
+
+/* ++from db_dump.c++ */
+extern int db_dump __P((struct hashbuf *, FILE *, int, char *)),
+ zt_dump __P((FILE *)),
+ atob __P((char *, int, char *, int, int *));
+extern void doachkpt __P((void)),
+ doadump __P((void));
+#ifdef ALLOW_UPDATES
+extern void zonedump __P((struct zoneinfo *));
+#endif
+/* --from db_dump.c-- */
+
+/* ++from db_load.c++ */
+extern void endline __P((FILE *)),
+ get_netlist __P((FILE *, struct netinfo **,
+ int, char *)),
+ free_netlist __P((struct netinfo **));
+extern int getword __P((char *, int, FILE *)),
+ getnum __P((FILE *, char *, int)),
+ db_load __P((char *, char *, struct zoneinfo *, int)),
+ position_on_netlist __P((struct in_addr,
+ struct netinfo *));
+extern struct netinfo *addr_on_netlist __P((struct in_addr,
+ struct netinfo *));
+/* --from db_load.c-- */
+
+/* ++from db_glue.c++ */
+extern void buildservicelist __P((void)),
+ buildprotolist __P((void)),
+ gettime __P((struct timeval *)),
+ getname __P((struct namebuf *, char *, int));
+extern int servicenumber __P((char *)),
+ protocolnumber __P((char *)),
+ my_close __P((int)),
+ my_fclose __P((FILE *)),
+#ifdef GEN_AXFR
+ get_class __P((char *)),
+#endif
+ writemsg __P((int, u_char *, int)),
+ dhash __P((u_char *, int)),
+ samedomain __P((const char *, const char *));
+extern char *protocolname __P((int)),
+ *servicename __P((u_int16_t, char *)),
+ *savestr __P((char *));
+#ifndef BSD
+extern int getdtablesize __P((void));
+#endif
+extern struct databuf *rm_datum __P((struct databuf *,
+ struct namebuf *,
+ struct databuf *));
+extern struct namebuf *rm_name __P((struct namebuf *,
+ struct namebuf **,
+ struct namebuf *));
+#ifdef INVQ
+extern void addinv __P((struct namebuf *, struct databuf *)),
+ rminv __P((struct databuf *));
+struct invbuf *saveinv __P((void));
+#endif
+/* --from db_glue.c-- */
+
+/* ++from db_lookup.c++ */
+extern struct namebuf *nlookup __P((char *, struct hashbuf **,
+ char **, int));
+extern int match __P((struct databuf *, int, int));
+/* --from db_lookup.c-- */
+
+/* ++from db_secure.c++ */
+#ifdef SECURE_ZONES
+extern int build_secure_netlist __P((struct zoneinfo *));
+#endif
+/* --from db_secure.c-- */
diff --git a/usr.sbin/named/db_glob.h b/usr.sbin/named/db_glob.h
new file mode 100644
index 0000000..74ae45d
--- /dev/null
+++ b/usr.sbin/named/db_glob.h
@@ -0,0 +1,93 @@
+/*
+ * from db.h 4.16 (Berkeley) 6/1/90
+ * $Id: db_glob.h,v 1.2 1994/04/12 08:57:50 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1985, 1990
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Global variables for data base routines.
+ */
+
+ /* ONE_WEEK maximum ttl */
+DECL int max_cache_ttl INIT(7*24*60*60);
+
+ /* 5 minute minimum ttl */
+DECL int min_cache_ttl INIT(5*60);
+
+ /* current line number */
+DECL int lineno;
+
+#ifdef DUMPFILE
+DECL char *dumpfile INIT(DUMPFILE);
+#else
+DECL char *dumpfile INIT(_PATH_DUMPFILE);
+#endif
+
+ /* root hash table */
+DECL struct hashbuf *hashtab INIT(NULL);
+
+ /* hash table of cache read from file */
+DECL struct hashbuf *fcachetab INIT(NULL);
+
+#ifdef INVQ
+ /* Inverse query hash table */
+DECL struct invbuf *invtab[INVHASHSZ];
+#endif
+
+#ifdef FORCED_RELOAD
+DECL int reloading INIT(0);
+#endif /* FORCED_RELOAD */
diff --git a/usr.sbin/named/db_glue.c b/usr.sbin/named/db_glue.c
new file mode 100644
index 0000000..f3f3069
--- /dev/null
+++ b/usr.sbin/named/db_glue.c
@@ -0,0 +1,710 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_glue.c 4.4 (Berkeley) 6/1/90";
+static char rcsid[] = "$Id: db_glue.c,v 4.9.1.12 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <errno.h>
+
+#include "named.h"
+
+struct valuelist {
+ struct valuelist *next, *prev;
+ char *name;
+ char *proto;
+ int port;
+} *servicelist, *protolist;
+
+#if defined(ultrix)
+/* ultrix 4.0 has some icky packaging details. work around them here.
+ * since this module is linked into named and named-xfer, we end up
+ * forcing both to drag in our own res_send rather than ultrix's hesiod
+ * version of that.
+ */
+static const int (*unused_junk)__P((const u_char *, int, u_char *, int)) =
+ res_send;
+;
+#endif
+
+void
+buildservicelist()
+{
+ struct servent *sp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setservent(0);
+#else
+ setservent(1);
+#endif
+ 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_int16_t)sp->s_port);
+ slp->next = servicelist;
+ slp->prev = NULL;
+ if (servicelist)
+ servicelist->prev = slp;
+ servicelist = slp;
+ }
+ endservent();
+}
+
+void
+buildprotolist()
+{
+ struct protoent *pp;
+ struct valuelist *slp;
+
+#ifdef MAYBE_HESIOD
+ setprotoent(0);
+#else
+ setprotoent(1);
+#endif
+ 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();
+}
+
+static int
+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);
+}
+
+/*
+ * Convert service name or (ascii) number to int.
+ */
+int
+servicenumber(p)
+ char *p;
+{
+ return (findservice(p, &servicelist));
+}
+
+/*
+ * Convert protocol name or (ascii) number to int.
+ */
+int
+protocolnumber(p)
+ char *p;
+{
+ return (findservice(p, &protolist));
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+static struct servent *
+cgetservbyport(u_int16_t port,
+ char *proto)
+#else
+static struct servent *
+cgetservbyport(port, proto)
+ u_int16_t port;
+ char *proto;
+#endif
+{
+ 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 != (u_int16_t)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_int16_t)lp->port);
+ serv.s_proto = lp->proto;
+ return (&serv);
+ }
+ }
+ return (0);
+}
+
+static 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);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+char *
+servicename(u_int16_t port, char *proto)
+#else
+char *
+servicename(port, proto)
+ u_int16_t port;
+ char *proto;
+#endif
+{
+ 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);
+}
+
+int
+db_getclev(origin)
+ char *origin;
+{
+ int lev = 0;
+ dprintf(1, (ddt, "db_getclev of \"%s\"", origin));
+ if (origin && *origin)
+ lev++;
+ while (origin && (origin = strchr(origin, '.'))) {
+ origin++;
+ lev++;
+ }
+ dprintf(1, (ddt, " = %d\n", lev));
+ return (lev);
+}
+
+void
+gettime(ttp)
+ struct timeval *ttp;
+{
+ if (gettimeofday(ttp, NULL) < 0)
+ syslog(LOG_ERR, "gettimeofday: %m");
+ return;
+}
+
+#if !defined(BSD)
+int
+getdtablesize()
+{
+#if defined(USE_POSIX)
+ int j = (int) sysconf(_SC_OPEN_MAX);
+
+ if (j >= 0)
+ return (j);
+#endif /* POSIX */
+ return (FD_SETSIZE);
+}
+#endif /* BSD */
+
+int
+my_close(fd)
+ int fd;
+{
+ int s = close(fd);
+
+ if (s < 0) {
+ syslog(LOG_ERR, "close(%d) failed: %m", fd);
+ dprintf(3, (ddt, "close(%d) failed: %s\n",
+ fd, strerror(errno)));
+ } else {
+ dprintf(3, (ddt, "close(%d) succeeded\n", fd));
+ }
+ return (s);
+}
+
+#ifdef GEN_AXFR
+/*
+ * Map class names to number
+ */
+struct map {
+ char *token;
+ int val;
+};
+
+static struct map map_class[] = {
+ "in", C_IN,
+ "chaos", C_CHAOS,
+ "hs", C_HS,
+ NULL, 0,
+};
+
+int
+get_class(class)
+ char *class;
+{
+ struct map *mp;
+
+ if (isdigit(*class))
+ return (atoi(class));
+ for (mp = map_class; mp->token != NULL; mp++)
+ if (strcasecmp(class, mp->token) == 0)
+ return (mp->val);
+ return (C_IN);
+}
+#endif
+
+int
+my_fclose(fp)
+ FILE *fp;
+{
+ int fd = fileno(fp),
+ s = fclose(fp);
+
+ if (s < 0) {
+ syslog(LOG_ERR, "fclose(%d) failed: %m", fd);
+ dprintf(3, (ddt, "fclose(%d) failed: %s\n",
+ fd, strerror(errno)));
+ } else {
+ dprintf(3, (ddt, "fclose(%d) succeeded\n", fd));
+ }
+ return (s);
+}
+
+/*
+ * Make a copy of a string and return a pointer to it.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *cp;
+
+ cp = (char *)malloc(strlen(str) + 1);
+ if (cp == NULL) {
+ syslog(LOG_ERR, "savestr: %m");
+ exit(1);
+ }
+ (void) strcpy(cp, str);
+ return (cp);
+}
+
+int
+writemsg(rfd, msg, msglen)
+ int rfd;
+ u_char *msg;
+ int msglen;
+{
+ struct iovec iov[2];
+ u_char len[INT16SZ];
+
+ __putshort(msglen, len);
+ iov[0].iov_base = (char *)len;
+ iov[0].iov_len = INT16SZ;
+ iov[1].iov_base = (char *)msg;
+ iov[1].iov_len = msglen;
+ if (writev(rfd, iov, 2) != INT16SZ + msglen) {
+ dprintf(1, (ddt, "write failed %d\n", errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/* rm_datum(dp, np, pdp)
+ * remove datum 'dp' from name 'np'. pdp is previous data pointer.
+ * return value:
+ * "next" field from removed datum, suitable for relinking
+ */
+struct databuf *
+rm_datum(dp, np, pdp)
+ register struct databuf *dp;
+ register struct namebuf *np;
+ register struct databuf *pdp;
+{
+ register struct databuf *ndp = dp->d_next;
+
+ dprintf(3, (ddt, "rm_datum(%x, %x, %x) -> %x\n",
+ dp, np->n_data, pdp, ndp));
+#ifdef INVQ
+ rminv(dp);
+#endif
+ if (pdp == NULL)
+ np->n_data = ndp;
+ else
+ pdp->d_next = ndp;
+#ifdef DATUMREFCNT
+ if (--(dp->d_rcnt)) {
+ switch(dp->d_type) {
+ case T_NS:
+ dprintf(1, (ddt, "rm_datum: %s rcnt = %d\n",
+ dp->d_data, dp->d_rcnt));
+ break;
+ case T_A:
+ dprintf(1, (ddt, "rm_datum: %08.8X rcnt = %d\n",
+ *(int32_t*)(dp->d_data), dp->d_rcnt));
+ break;
+ default:
+ dprintf(1, (ddt, "rm_datum: rcnt = %d\n", dp->d_rcnt));
+ }
+ } else
+#endif
+ free((char *)dp);
+ return (ndp);
+}
+
+/* rm_name(np, he, pnp)
+ * remove name 'np' from parent 'pp'. pnp is previous name pointer.
+ * return value:
+ * "next" field from removed name, suitable for relinking
+ */
+struct namebuf *
+rm_name(np, pp, pnp)
+ struct namebuf *np, **pp, *pnp;
+{
+ struct namebuf *nnp = np->n_next;
+ char *msg;
+
+ /* verify */
+ if ( (np->n_data && (msg = "data"))
+ || (np->n_hash && (msg = "hash"))
+ ) {
+ dprintf(1, (ddt,
+ "rm_name(%x(%s)): non-nil %s pointer\n",
+ np, np->n_dname?np->n_dname:"Nil", msg));
+ syslog(LOG_ERR,
+ "rm_name(%x(%s)): non-nil %s pointer\n",
+ np, np->n_dname?np->n_dname:"Nil", msg);
+ abort();
+ }
+
+ /* unlink */
+ if (pnp) {
+ pnp->n_next = nnp;
+ } else {
+ *pp = nnp;
+ }
+
+ /* deallocate */
+ free(np->n_dname);
+ free((char*) np);
+
+ /* done */
+ return (nnp);
+}
+
+/*
+ * Get the domain name of 'np' and put in 'buf'. Bounds checking is done.
+ */
+void
+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';
+}
+
+#ifdef INVQ
+/*
+ * Add data 'dp' to inverse query tables for name 'np'.
+ */
+void
+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.
+ */
+void
+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 (dp != odp)
+ continue;
+ while (i < INVBLKSZ-1) {
+ ip->i_dname[i] = ip->i_dname[i+1];
+ i++;
+ }
+ ip->i_dname[i] = NULL;
+ return;
+ }
+ }
+ }
+}
+
+/*
+ * 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);
+}
+#endif /*INVQ*/
+
+/*
+ * Compute hash value from data.
+ */
+int
+dhash(dp, dlen)
+ u_char *dp;
+ int dlen;
+{
+ register u_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);
+}
+
+/*
+** SAMEDOMAIN -- Check whether a name belongs to a domain
+** ------------------------------------------------------
+**
+** Returns:
+** TRUE if the given name lies in the domain.
+** FALSE otherwise.
+**
+** Trailing dots are first removed from name and domain.
+** Always compare complete subdomains, not only whether the
+** domain name is the trailing string of the given name.
+**
+** "host.foobar.top" lies in "foobar.top" and in "top" and in ""
+** but NOT in "bar.top"
+**
+** this implementation of samedomain() is thanks to Bob Heiney.
+*/
+
+int
+samedomain(a, b)
+ const char *a, *b;
+{
+ size_t la, lb;
+ const char *cp;
+
+ la = strlen(a);
+ lb = strlen(b);
+
+ /* don't count trailing dots, if any. */
+ if (la && a[la-1]=='.')
+ la--;
+ if (lb && b[lb-1]=='.')
+ lb--;
+
+ /* lb==0 means b is the root domain, so a must be in b. */
+ if (lb == 0)
+ return (1);
+
+ /* b longer than a means a can't be in b. */
+ if (lb > la)
+ return (0);
+
+ /* We use strncasecmp because we might be trying to
+ * ignore trailing dots. */
+ if (lb == la)
+ return (strncasecmp(a, b, lb) == 0);
+
+ /* Ok, we know la > lb. */
+
+ /* Point at the character before the last 'lb' characters of a. */
+ cp = a + (la - lb - 1);
+
+ /* If it isn't '.', can't be a match (this lets us avoid
+ * having "foobar.com" match "bar.com"). */
+ if (*cp != '.')
+ return (0);
+
+ cp++;
+
+ /* We use strncasecmp because we might be trying to
+ * ignore trailing dots. */
+ return (strncasecmp(cp, b, lb)==0);
+}
diff --git a/usr.sbin/named/db_load.c b/usr.sbin/named/db_load.c
new file mode 100644
index 0000000..ef6d0b4
--- /dev/null
+++ b/usr.sbin/named/db_load.c
@@ -0,0 +1,1218 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_load.c 4.38 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: db_load.c,v 4.9.1.18 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Load data base from ascii backupfile. Format similar to RFC 883.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <netiso/iso.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <netdb.h>
+
+#include "named.h"
+
+static int gettoken __P((register FILE *, char *)),
+ getnonblank __P((FILE *, char *)),
+ getprotocol __P((FILE *, char *)),
+ getservices __P((int, char *, FILE *, char *));
+static void makename __P((char *, char *));
+static int empty_token = 0;
+
+/*
+ * 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,
+ "rp", T_RP,
+ "afsdb", T_AFSDB,
+ "x25", T_X25,
+ "isdn", T_ISDN,
+ "rt", T_RT,
+ "nsap", T_NSAP,
+ "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
+
+static int clev; /* a zone deeper in a heirachy has more credability */
+
+/* int
+ * db_load(filename, in_origin, zp, doinginclude)
+ * load a database from `filename' into zone `zp'. append `origin'
+ * to all nonterminal domain names in the file. `doinginclude' is
+ * true if this is a $INCLUDE file.
+ * returns:
+ * -1 = can't open file
+ * 0 = success
+ * >0 = number of errors encountered
+ */
+int
+db_load(filename, in_origin, zp, doinginclude)
+ char *filename, *in_origin;
+ struct zoneinfo *zp;
+ int doinginclude;
+{
+ register char *cp;
+ register struct map *mp;
+ char domain[MAXDNAME];
+ char origin[MAXDNAME];
+ char tmporigin[MAXDNAME];
+ char buf[MAXDATA];
+ char data[MAXDATA];
+ char *cp1;
+ char *op;
+ int c, class, type, ttl, dbflags, dataflags, multiline;
+ static int read_soa; /* number of soa's read */
+ struct databuf *dp;
+ struct iso_addr *isoa;
+ FILE *fp;
+ int slineno, i, errs = 0, didinclude = 0;
+ register u_int32_t n;
+ struct stat sb;
+ struct in_addr ina;
+
+ if (!doinginclude) {
+ read_soa = 0;
+ clev = db_getclev(in_origin);
+ }
+
+ dprintf(1, (ddt,"db_load(%s, %s, %d, %d)\n",
+ filename, in_origin, zp - zones, doinginclude));
+
+ (void) strcpy(origin, in_origin);
+ if ((fp = fopen(filename, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", filename);
+ dprintf(1, (ddt, "db_load: error opening file %s\n",
+ filename));
+ 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 = zp->z_class;
+ zp->z_flags &= ~(Z_INCLUDE|Z_DB_BAD);
+ while ((c = gettoken(fp, filename)) != EOF) {
+ switch (c) {
+ case INCLUDE:
+ if (!getword((char *)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((char *)buf, tmporigin, zp, 1);
+ continue;
+
+ case ORIGIN:
+ (void) strcpy((char *)buf, origin);
+ if (!getword(origin, sizeof(origin), fp))
+ break;
+ dprintf(3, (ddt, "db_load: origin %s, buf %s\n",
+ origin, buf));
+ makename(origin, buf);
+ dprintf(3, (ddt, "db_load: origin now %s\n", origin));
+ 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((char *)buf, sizeof(buf), fp)) {
+ if (c == CURRENT)
+ continue;
+ break;
+ }
+ cp = buf;
+ ttl = 0;
+ if (isdigit(*cp)) {
+ n = 0;
+ do {
+ if (n > (INT_MAX - (*cp - '0')) / 10) {
+ syslog(LOG_ERR,
+ "%s: line %d: number > %lu\n",
+ filename, lineno, INT_MAX);
+ dprintf(1, (ddt,
+ "%s: line %d: number > %lu\n",
+ filename, lineno, INT_MAX));
+ n = INT_MAX;
+ cp++;
+ } else
+ 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((char *)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((char *)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;
+ }
+ dprintf(1, (ddt, "%s: Line %d: Unknown type: %s.\n",
+ filename, lineno, buf));
+ errs++;
+ syslog(LOG_ERR, "%s: Line %d: Unknown type: %s.\n",
+ filename, 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
+ if (!getword((char *)buf, sizeof(buf), fp))
+ break;
+ dprintf(3,
+ (ddt,
+ "d='%s', c=%d, t=%d, ttl=%d, data='%s'\n",
+ domain, class, type, ttl, buf));
+#ifdef ALLOW_T_UNSPEC
+ }
+#endif
+ /*
+ * Convert the ascii data 'buf' to the proper format
+ * based on the type and pack into 'data'.
+ */
+ switch (type) {
+ case T_A:
+ if (!inet_aton(buf, &ina))
+ goto err;
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ n = INT32SZ;
+ break;
+
+ case T_HINFO:
+ case T_ISDN:
+ 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);
+ if (n == 0)
+ goto err;
+ n++;
+ if (!getword((char *)buf, sizeof(buf), fp))
+ i = 0;
+ else {
+ endline(fp);
+ i = strlen((char *)buf);
+ }
+ if (i == 0) {
+ /* goto err; */
+ /* XXX tolerate for now */
+ data[n++] = 1;
+ data[n++] = '?';
+ break;
+ }
+ if (i > 255) {
+ syslog(LOG_WARNING,
+ "%s:%d: OS type too long",
+ filename, lineno);
+ i = 255;
+ }
+ data[n] = i;
+ bcopy(buf, data + n + 1, i);
+ n += i + 1;
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ (void) strcpy((char *)data, (char *)buf);
+ makename(data, origin);
+ cp = data + strlen((char *)data) + 1;
+ if (!getword((char *)cp,
+ sizeof(data) - (cp - data), fp))
+ goto err;
+ makename(cp, origin);
+ cp += strlen((char *)cp) + 1;
+ if (type != T_SOA) {
+ n = cp - data;
+ break;
+ }
+ if (class != zp->z_class) {
+ syslog(LOG_WARNING,
+ "%s:%d: %s",
+ filename, lineno,
+ "SOA class not same as zone's");
+ }
+ c = getnonblank(fp, filename);
+ if (c == '(') {
+ multiline = 1;
+ } else {
+ multiline = 0;
+ ungetc(c, fp);
+ }
+ zp->z_serial = getnum(fp, filename, 1);
+ n = (u_int32_t) zp->z_serial;
+ PUTLONG(n, cp);
+ zp->z_refresh = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_refresh;
+ PUTLONG(n, cp);
+ if (zp->z_type == Z_SECONDARY
+#if defined(STUBS)
+ || zp->z_type == Z_STUB
+#endif
+ ) {
+ zp->z_time = sb.st_mtime
+ + zp->z_refresh;
+ }
+ zp->z_retry = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_retry;
+ PUTLONG(n, cp);
+ zp->z_expire = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_expire;
+ PUTLONG (n, cp);
+ zp->z_minimum = getnum(fp, filename, 0);
+ n = (u_int32_t) zp->z_minimum;
+ PUTLONG (n, cp);
+ n = cp - data;
+ if (multiline) {
+ if (getnonblank(fp, filename) != ')')
+ 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 = INT32SZ;
+ break;
+
+ case T_WKS:
+ /* Address */
+ if (!inet_aton(buf, &ina))
+ goto err;
+ n = ntohl(ina.s_addr);
+ cp = data;
+ PUTLONG(n, cp);
+ *cp = (char)getprotocol(fp, filename);
+ /* Protocol */
+ n = INT32SZ + 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 = strchr((char *)buf, '&');
+ bzero(data, sizeof(data));
+ if ( cp != NULL) {
+ (void) strncpy((char *)data,
+ (char *)buf, cp - buf);
+ op = strchr(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:
+ case T_AFSDB:
+ case T_RT:
+ 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_int16_t)n, cp);
+
+ if (!getword((char *)buf, sizeof(buf), fp))
+ goto err;
+ (void) strcpy((char *)cp, (char *)buf);
+ makename(cp, origin);
+ /* advance pointer to end of data */
+ cp += strlen((char *)cp) +1;
+
+ /* now save length */
+ n = (cp - data);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ cp = buf + (n = strlen(buf));
+ while ((i = getc(fp), *cp = i, i != EOF)
+ && *cp != '\n'
+ && (n < MAXDATA)) {
+ cp++; n++;
+ }
+ if (*cp == '\n') /* leave \n for getword */
+ ungetc(*cp, fp);
+ *cp = '\0';
+ /* now do normal processing */
+
+ 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;
+
+ case T_NSAP:
+ isoa = iso_addr(buf);
+ if (!isoa)
+ goto err;
+ n = isoa->isoa_len;
+ bcopy(isoa->isoa_genaddr, data, n);
+ endline(fp);
+ break;
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+ {
+ int rcode;
+ fgets(buf, sizeof(buf), fp);
+ dprintf(1, (ddt, "loading T_UNSPEC\n"));
+ if (rcode = atob(buf,
+ strlen((char*)buf),
+ data, sizeof(data),
+ &n)) {
+ if (rcode == CONV_OVERFLOW) {
+ dprintf(1,
+ (ddt,
+ "Load T_UNSPEC: input buffer overflow\n"
+ )
+ );
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: input buffer overflow");
+ } else {
+ dprintf(1,
+ (ddt,
+ "Load T_UNSPEC: Data in bad atob format\n"
+ )
+ );
+ errs++;
+ syslog(LOG_ERR,
+ "Load T_UNSPEC: Data in bad atob format");
+ }
+ }
+ }
+ break;
+#endif /* ALLOW_T_UNSPEC */
+
+ default:
+ goto err;
+ }
+#ifdef STUBS
+ if (type == T_SOA && zp->z_type == Z_STUB)
+ continue;
+#endif
+#ifdef NO_GLUE
+ /*
+ * Ignore data outside the zone.
+ */
+ if (zp->z_type != Z_CACHE &&
+ !samedomain(domain, zp->z_origin))
+ {
+ syslog(LOG_WARNING,
+ "%s:%d: data \"%s\" outside zone \"%s\" (ignored)",
+ filename, lineno, domain, zp->z_origin);
+ continue;
+ }
+#endif /*NO_GLUE*/
+
+ dp = savedata(class, type, (u_int32_t)ttl,
+ (u_char *)data, (int)n);
+ dp->d_zone = zp - zones;
+ dp->d_flags = dataflags;
+ dp->d_cred = DB_C_ZONE;
+ dp->d_clev = clev;
+ if ((c = db_update(domain, dp, dp, dbflags,
+ (zp->z_type == Z_CACHE)
+ ? fcachetab
+ : hashtab))
+ != OK) {
+#ifdef DEBUG
+ if (debug && (c != DATAEXISTS))
+ fprintf(ddt, "update failed %s %d\n",
+ domain, type);
+#endif
+ free((char*) dp);
+ }
+ continue;
+
+ case ERROR:
+ break;
+ }
+ err:
+ errs++;
+ syslog(LOG_ERR, "%s: line %d: database format error (%s)",
+ filename, empty_token ? (lineno - 1) : lineno, buf);
+ dprintf(1, (ddt,
+ "%s: line %d: database format error ('%s', %d)\n",
+ filename, empty_token ? (lineno - 1) : lineno,
+ buf, n));
+ while ((c = getc(fp)) != EOF && c != '\n')
+ ;
+ if (c == '\n')
+ lineno++;
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+ if (doinginclude == 0) {
+ if (didinclude) {
+ zp->z_flags |= 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);
+ }
+ }
+#ifdef SECURE_ZONES
+ build_secure_netlist(zp);
+#endif
+ if (errs)
+ zp->z_flags |= Z_DB_BAD;
+ return (errs);
+}
+
+static int
+gettoken(fp, src)
+ register FILE *fp;
+ char *src;
+{
+ 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);
+ }
+ dprintf(1, (ddt,
+ "%s: line %d: Unknown $ option: $%s\n",
+ src, lineno, op));
+ syslog(LOG_ERR,"%s: line %d: Unknown $ option: $%s\n",
+ src, 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);
+ }
+ }
+}
+
+/* int
+ * getword(buf, size, fp)
+ * get next word, skipping blanks & comments.
+ * parameters:
+ * buf - destination
+ * size - of destination
+ * fp - file to read from
+ * return value:
+ * 0 = no word; perhaps EOL or EOF
+ * 1 = word was read
+ */
+int
+getword(buf, size, fp)
+ char *buf;
+ int size;
+ FILE *fp;
+{
+ register char *cp;
+ register int c;
+
+ empty_token = 0;
+ 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;
+ }
+ if ((c = getc(fp)) != EOF)
+ ungetc(c, fp);
+ if (c == EOF || isspace(c) || c == '\n') {
+ *cp = '\0';
+ return (1);
+ }
+ else
+ continue;
+ }
+ if (c == '\\') {
+ if ((c = getc(fp)) == EOF)
+ c = '\\';
+ if (c == '\n')
+ lineno++;
+ }
+ if (cp >= buf+size-1)
+ break;
+ *cp++ = (char)c;
+ }
+ *cp = '\0';
+ if (cp == buf)
+ empty_token = 1;
+ return (cp != buf);
+}
+
+/*
+From: kagotani@cs.titech.ac.jp
+Message-Id: <9007040716.AA26646@saeko.cs.titech.ac.jp>
+Subject: named bug report and fix
+Date: Wed, 04 Jul 90 16:16:52 JST
+
+I found a bug in the BIND source code. Named with this bug parses
+the serial_no field of SOA records incorrectly. For example:
+ expression internal
+ in files expression I expect
+ 1. 1000 10000
+ 1.2 10002 10002
+ 1.23 100023 10023
+ 2.3 20003 20003
+Especially I can not accept that "2.3" is treated as if it is
+smaller than "1.23" in their internal expressions.
+
+[ if you define SENSIBLE_DOTS in ../conf/options.h, you get
+ m. kagotani's expected behaviour. this is NOT compatible
+ with pre-4.9 versions of BIND. --vix ]
+*/
+
+int
+getnum(fp, src, is_serial)
+ FILE *fp;
+ char *src;
+ int is_serial;
+{
+ register int c, n;
+ int seendigit = 0;
+ int seendecimal = 0;
+ int m = 0;
+ int allow_dots = 0;
+
+#ifdef DOTTED_SERIAL
+ allow_dots += is_serial;
+#endif
+ 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 != '.' || !allow_dots) {
+ syslog(LOG_ERR, "%s:%d: expected a number",
+ src, lineno);
+ dprintf(1, (ddt, "%s:%d: expected a number",
+ src, lineno));
+ exit(1); /* XXX why exit here?? */
+ } else {
+ if (!seendigit)
+ n = 1;
+#ifdef SENSIBLE_DOTS
+ n = n * 10000;
+#else
+ n = n * 1000;
+#endif
+ seendigit = 1;
+ seendecimal = 1;
+ }
+ continue;
+ }
+#ifdef SENSIBLE_DOTS
+ if (seendecimal)
+ m = m * 10 + (c - '0');
+ else
+ n = n * 10 + (c - '0');
+#else
+ n = n * 10 + (c - '0');
+#endif
+ seendigit = 1;
+ }
+ if (m > 9999) {
+ syslog(LOG_ERR,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno);
+ dprintf(1, (ddt,
+ "%s:%d: number after the decimal point exceeds 9999",
+ src, lineno));
+ exit(1); /* XXX why exit here?? */
+ }
+ if (seendecimal) {
+ syslog(LOG_INFO,
+ "%s:%d: decimal serial number interpreted as %d",
+ src, lineno, n+m);
+ }
+ return (n + m);
+}
+
+static int
+getnonblank(fp, src)
+ FILE *fp;
+ char *src;
+{
+ 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, "%s: line %d: unexpected EOF", src, lineno);
+ dprintf(1, (ddt, "%s: line %d: unexpected EOF", src, lineno));
+ return (EOF);
+}
+
+/*
+ * Take name and fix it according to following rules:
+ * "." means root.
+ * "@" means current origin.
+ * "name." means no changes.
+ * "name" means append origin.
+ */
+static void
+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);
+ }
+ }
+}
+
+void
+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
+
+static int
+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);
+}
+
+static 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);
+ dprintf(1, (ddt,
+ "%s: line %d: port no. (%d) too big\n",
+ src, lineno, k));
+ }
+ }
+ 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_netlist(fp, netlistp, allow)
+ * get list of nets from 'fp', put on *netlistp, 'allow' controls
+ * whether hosts, nets, or both shall be accepted without warnings.
+ * (note that they are always accepted; 'allow' just controls the
+ * warnings.)
+ */
+void
+get_netlist(fp, netlistp, allow, print_tag)
+ FILE *fp;
+ struct netinfo **netlistp;
+ int allow;
+ char *print_tag;
+{
+ struct netinfo *ntp = NULL, **end = netlistp;
+ char buf[BUFSIZ], *maskp;
+ struct in_addr ina;
+
+ dprintf(1, (ddt, "get_netlist(%s)", print_tag));
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+ if ((maskp = strchr(buf, '&')) != NULL)
+ *maskp++ = '\0';
+ dprintf(1, (ddt," %s", buf));
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ syslog(LOG_ERR, "%s contains bogus element (%s)",
+ print_tag, buf);
+ continue;
+ }
+ if (maskp) {
+ if (!inet_aton(maskp, &ina)) {
+ syslog(LOG_ERR,
+ "%s element %s has bad mask (%s)",
+ print_tag, buf, maskp);
+ continue;
+ }
+ } else {
+ if (allow & ALLOW_HOSTS)
+ ina.s_addr = 0xffffffff; /* "exact" */
+ else
+ ina.s_addr = net_mask(ntp->my_addr);
+ }
+ ntp->next = NULL;
+ ntp->mask = ina.s_addr;
+ ntp->addr = ntp->my_addr.s_addr & ntp->mask;
+
+ /* Check for duplicates */
+ if (addr_on_netlist(ntp->my_addr, *netlistp))
+ continue;
+
+ if (ntp->addr != ntp->my_addr.s_addr) {
+ ina.s_addr = ntp->addr;
+ syslog(LOG_WARNING,
+ "%s element (%s) mask problem (%s)",
+ print_tag, buf, inet_ntoa(ina));
+ }
+
+ *end = ntp;
+ end = &ntp->next;
+ ntp = NULL;
+ }
+ if (ntp)
+ free((char *)ntp);
+
+ dprintf(1, (ddt, "\n"));
+#ifdef DEBUG
+ if (debug > 2)
+ for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt, "ntp x%x addr x%x mask x%x",
+ ntp, ntp->addr, ntp->mask);
+ fprintf(ddt, " my_addr x%x", ntp->my_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%x\n", ntp->next);
+ }
+#endif
+}
+
+struct netinfo *
+addr_on_netlist(addr, netlist)
+ struct in_addr addr;
+ struct netinfo *netlist;
+{
+ u_int32_t a = addr.s_addr;
+ struct netinfo *t;
+
+ for (t = netlist; t != NULL; t = t->next)
+ if (t->addr == (a & t->mask))
+ return t;
+ return NULL;
+}
+
+int
+position_on_netlist(addr, netlist)
+ struct in_addr addr;
+ struct netinfo *netlist;
+{
+ u_int32_t a = addr.s_addr;
+ struct netinfo *t;
+ int position = 0;
+
+ for (t = netlist; t != NULL; t = t->next)
+ if (t->addr == (a & t->mask))
+ break;
+ else
+ position++;
+ return position;
+}
+
+void
+free_netlist(netlistp)
+ struct netinfo **netlistp;
+{
+ register struct netinfo *ntp, *next;
+
+ for (ntp = *netlistp; ntp != NULL; ntp = next) {
+ next = ntp->next;
+ free((char *)ntp);
+ }
+ *netlistp = NULL;
+}
diff --git a/usr.sbin/named/db_lookup.c b/usr.sbin/named/db_lookup.c
new file mode 100644
index 0000000..9084491
--- /dev/null
+++ b/usr.sbin/named/db_lookup.c
@@ -0,0 +1,196 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_lookup.c 4.18 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_lookup.c,v 4.9.1.5 1994/06/01 21:09:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Table lookup routines.
+ */
+
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "named.h"
+
+/*
+ * 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 += (isupper(c) ? tolower(c) : 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) {
+ *fname = name;
+ *cp = c;
+ 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) {
+ *fname = name;
+ *cp = c;
+ 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;
+ }
+ *fname = name;
+ *cp = c;
+ return (np);
+}
+
+/* int
+ * match(dp, class, type)
+ * Does data record `dp' match the class and type?
+ * return value:
+ * boolean
+ */
+int
+match(dp, class, type)
+ register struct databuf *dp;
+ register int class, type;
+{
+ dprintf(5, (ddt, "match(0x%x, %d, %d) %d, %d\n",
+ dp, class, type, dp->d_class, dp->d_type));
+ 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 0000000..1b962a6
--- /dev/null
+++ b/usr.sbin/named/db_reload.c
@@ -0,0 +1,125 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_reload.c 4.22 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_reload.c,v 4.9.1.4 1994/07/02 16:28:11 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+
+#include "named.h"
+
+/*
+ * Flush and reload data base.
+ */
+void
+db_reload()
+{
+ dprintf(3, (ddt, "reload()\n"));
+ syslog(LOG_NOTICE, "reloading nameserver\n");
+
+ qflush();
+ sqflush(NULL);
+ getnetconf();
+#ifdef FORCED_RELOAD
+ reloading = 1; /* to force transfer if secondary and backing up */
+#endif
+ ns_init(bootfile);
+ time(&resettime);
+#ifdef FORCED_RELOAD
+ reloading = 0;
+ if (!needmaint)
+ sched_maint();
+#endif /* FORCED_RELOAD */
+
+ dprintf(1, (ddt, "Ready to answer queries.\n"));
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+}
+
+#if 0
+/* someday we'll need this.. (untested since before 1990) */
+void
+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);
+}
+#endif
diff --git a/usr.sbin/named/db_save.c b/usr.sbin/named/db_save.c
new file mode 100644
index 0000000..cd1639d
--- /dev/null
+++ b/usr.sbin/named/db_save.c
@@ -0,0 +1,214 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_save.c 4.16 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_save.c,v 4.9.1.7 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Buffer allocation and deallocation routines.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <stdio.h>
+
+#include "named.h"
+
+/*
+ * 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 *
+#ifdef DMALLOC
+savedata_tagged(file, line, class, type, ttl, data, size)
+ char *file;
+ int line;
+#else
+savedata(class, type, ttl, data, size)
+#endif
+ int class, type;
+ u_int32_t ttl;
+ u_char *data;
+ int size;
+{
+ register struct databuf *dp;
+
+ if (type == T_NS)
+ dp = (struct databuf *)
+#ifdef DMALLOC
+ dmalloc(file, line,
+#else
+ malloc(
+#endif
+ (unsigned)DATASIZE(size)+INT32SZ);
+ else
+ dp = (struct databuf *)
+#ifdef DMALLOC
+ dmalloc(file, line,
+#else
+ malloc(
+#endif
+ (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_cred = 0;
+ dp->d_clev = 0;
+#ifdef NCACHE
+ dp->d_rcode = NOERROR;
+#endif
+#ifdef STATS
+ dp->d_ns = NULL;
+#endif
+ 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;
+ }
+ dprintf(4, (ddt, "savehash GROWING to %d\n", newsize));
+ 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 namebuf *));
+ if (oldhtp == NULL) {
+ htp->h_cnt = 0;
+ return (htp);
+ }
+ dprintf(4, (ddt, "savehash(%#x) cnt=%d, sz=%d, newsz=%d\n",
+ oldhtp, oldhtp->h_cnt, oldhtp->h_size, newsize));
+ 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);
+}
diff --git a/usr.sbin/named/db_secure.c b/usr.sbin/named/db_secure.c
new file mode 100644
index 0000000..b3eb731
--- /dev/null
+++ b/usr.sbin/named/db_secure.c
@@ -0,0 +1,170 @@
+#ifndef LINT
+static char rcsid[] = "$Id: db_secure.c,v 1.6 1994/07/23 23:23:56 vixie Exp $";
+#endif
+
+/* this file was contributed by Gregory Neil Shapiro of WPI in August 1993 */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+
+#include "named.h"
+
+#ifdef SECURE_ZONES
+
+#ifndef SECURE_ZONE_RR
+#define SECURE_ZONE_RR "secure_zone"
+#endif
+#ifndef MASK_SEP
+#define MASK_SEP ':'
+#endif
+
+int
+build_secure_netlist(zp)
+ struct zoneinfo *zp;
+{
+ struct netinfo *ntp = NULL, **netlistp, **end;
+ char buf[BUFSIZ];
+ struct hashbuf *htp;
+ struct namebuf *snp;
+ struct databuf *dp;
+ char *fname, *dname, dnbuf[MAXDNAME];
+ int errs = 0, securezone = 0;
+
+ if (zp->secure_nets) {
+ free_netlist(&zp->secure_nets);
+ }
+ netlistp = &zp->secure_nets;
+ end = netlistp;
+ strcat(strcat(strcpy(dnbuf, SECURE_ZONE_RR), "."), zp->z_origin);
+
+ dname = dnbuf;
+ htp = hashtab;
+ if ((snp = nlookup(dname, &htp, &fname, 0)) == NULL) {
+ dprintf(1, (ddt,
+ "build_secure_netlist(%s): FAIL on nlookup %s\n",
+ zp->z_origin, dname));
+ zp->secure_nets=NULL;
+ return(0);
+ }
+ /* A parent's RR's aren't valid */
+ if (strcasecmp(snp->n_dname, SECURE_ZONE_RR)) {
+ zp->secure_nets=NULL;
+ return(0);
+ }
+ /* Collect secure nets into secure_nets */
+ for (dp = snp->n_data; dp != NULL; dp = dp->d_next) {
+ char *maskptr = NULL;
+ if (!match(dp, C_ANY, T_TXT)) {
+ continue;
+ }
+ bzero(buf, sizeof(buf));
+ bcopy(dp->d_data+1, buf, dp->d_size-1);
+ maskptr=strchr(buf, MASK_SEP);
+ if (maskptr) {
+ *maskptr++ = 0;
+ }
+ dprintf(3, (ddt,
+ "build_secure_netlist(%s): Found secure zone %s\n",
+ zp->z_origin, buf));
+ if (ntp == NULL) {
+ ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+ if (!ntp) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): malloc fail\n",
+ zp->z_origin));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Out of Memory",
+ zp->z_origin);
+ if (!securezone) {
+ zp->secure_nets=NULL;
+ }
+ return(1);
+ }
+ }
+ if (!inet_aton(buf, &ntp->my_addr)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): Bad address: %s\n",
+ zp->z_origin, buf));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Bad address: %s",
+ zp->z_origin, buf);
+ errs++;
+ continue;
+ }
+ if (maskptr && *maskptr) {
+ if (*maskptr == 'h' || *maskptr == 'H') {
+ ntp->mask = (u_int32_t)-1;
+ } else {
+ if (!inet_aton(maskptr,
+ (struct in_addr *)&ntp->mask)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): Bad mask: %s\n",
+ zp->z_origin, maskptr));
+ syslog(LOG_ERR,
+ "build_secure_netlist (%s): Bad mask: %s",
+ zp->z_origin, maskptr);
+ errs++;
+ continue;
+ }
+ }
+ } else {
+ ntp->mask = net_mask(ntp->my_addr);
+ }
+ if (ntp->my_addr.s_addr & ~(ntp->mask)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): addr (%s) is not in mask (x%x)\n",
+ zp->z_origin,
+ inet_ntoa(ntp->my_addr),
+ ntp->mask));
+ syslog(LOG_WARNING,
+ "build_secure_netlist (%s): addr (%s) is not in mask (x%x)",
+ zp->z_origin,
+ inet_ntoa(ntp->my_addr),
+ ntp->mask);
+ errs++;
+ }
+ ntp->next = NULL;
+ ntp->addr = ntp->my_addr.s_addr & ntp->mask;
+
+ /* Check for duplicates */
+ if (addr_on_netlist(ntp->my_addr, *netlistp)) {
+ dprintf(1, (ddt,
+ "build_secure_netlist (%s): duplicate address %s\n",
+ zp->z_origin, inet_ntoa(ntp->my_addr)));
+ syslog(LOG_WARNING,
+ "build_secure_netlist (%s): duplicate address %s\n",
+ zp->z_origin, inet_ntoa(ntp->my_addr));
+ errs++;
+ continue;
+ }
+ *end = ntp;
+ end = &ntp->next;
+ ntp = NULL;
+ securezone++;
+ }
+ if (ntp) {
+ free((char *)ntp);
+ }
+ if (!securezone) {
+ zp->secure_nets=NULL;
+ }
+
+#ifdef DEBUG
+ if (debug > 1) {
+ for (ntp = *netlistp; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt, "ntp x%x addr x%x mask x%x",
+ ntp, ntp->addr, ntp->mask);
+ fprintf(ddt, " my_addr x%x", ntp->my_addr);
+ fprintf(ddt, " %s", inet_ntoa(ntp->my_addr));
+ fprintf(ddt, " next x%x\n", ntp->next);
+ }
+ }
+#endif
+ return(errs);
+}
+#endif /*SECURE_ZONES*/
diff --git a/usr.sbin/named/db_update.c b/usr.sbin/named/db_update.c
new file mode 100644
index 0000000..9324493
--- /dev/null
+++ b/usr.sbin/named/db_update.c
@@ -0,0 +1,638 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)db_update.c 4.28 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: db_update.c,v 4.9.1.19 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include "named.h"
+
+static void fixttl __P((struct databuf *));
+static int db_cmp __P((struct databuf *,
+ struct databuf *));
+
+/* int
+ * isRefByNS(name, htp)
+ * recurse through all of `htp' looking for NS RR's that refer to `name'.
+ * returns:
+ * nonzero if at least one such NS RR exists
+ * cautions:
+ * this is very expensive; probably you only want to use on fcachetab.
+ */
+static int
+isRefByNS(name, htp)
+ char name[];
+ struct hashbuf *htp;
+{
+ register struct namebuf *np;
+ register struct databuf *dp;
+
+ for (np = htp->h_tab[0]; np != NULL; np = np->n_next) {
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if ((dp->d_class == C_ANY || dp->d_class == C_IN) &&
+ (dp->d_type == T_NS) &&
+#ifdef NCACHE
+ (!dp->d_rcode) &&
+#endif
+ !strcasecmp(name, (char *)dp->d_data)) {
+ return (1);
+ }
+ }
+ if (np->n_hash && isRefByNS(name, np->n_hash)) {
+ return (1);
+ }
+ }
+ return (0);
+}
+
+
+/* int
+ * findMyZone(struct namebuf *np)
+ * surf the zone cuts and find this zone the hard way
+ * return value:
+ * zone number or DB_Z_CACHE if it's outside a zone
+ * interesting cases:
+ * DEC.COM SOA (primary)
+ * CRL.DEC.COM NS (in primary)
+ * if you start at CRL.. here, you find the DEC.COM zone
+ * if you start at NS.CRL.. here, you're in the cache
+ * DEC.COM SOA (primary)
+ * CRL.DEC.COM NS (in primary)
+ * CRL.DEC.COM SOA (secondary)
+ * CRL.DEC.COM NS (in secondary)
+ * if you start at CRL.. here, you find the CRL.DEC.COM zone
+ * if you start at NS.CRL.. here, you're in the CRL.. zone
+ */
+int
+findMyZone(np, class)
+ struct namebuf *np;
+ register int class;
+{
+ for (; np; np = np->n_parent) {
+ register struct databuf *dp;
+
+ /* if we encounter an SOA, we're in its zone (which can be
+ * the cache or an authoritative zone, depending).
+ */
+ for (dp = np->n_data; dp; dp = dp->d_next)
+ if (match(dp, class, T_SOA))
+ return (dp->d_zone);
+
+ /* if we find an NS at some node without having seen an SOA
+ * (above), then we're out in the cache somewhere.
+ */
+ for (dp = np->n_data; dp; dp = dp->d_next)
+ if (match(dp, class, T_NS))
+ return (DB_Z_CACHE);
+ }
+
+ /* getting all the way to the root without finding an NS or SOA
+ * probably means that we are in deep dip, but we'll treat it as
+ * being in the cache. (XXX?)
+ */
+ return (DB_Z_CACHE);
+}
+
+
+/* int
+ * db_update(name, odp, newdp, flags, htp)
+ * update data base node at `name'. `flags' controls the action.
+ * side effects:
+ * inverse query tables modified, if we're using them.
+ * return value:
+ * OK - success
+ * NONAME - name doesn't exist
+ * AUTH - you can't do that
+ * DATAEXISTS - there's something there and DB_NODATA was specified
+ * NODATA - there's no data, and (DB_DELETE or DB_MEXIST) was spec'd
+ *
+ * Policy: How to add data if one more RR is -ve data
+ *
+ * NEND NOERROR_NODATA
+ * NXD NXDOMAIN
+ *
+ * match
+ * old
+ * Data NEND NXD
+ * Data Merge Data Data
+ * new NEND NEND NEND NEND
+ * NXD NXD NXD NXD
+ *
+ * no match
+ * old
+ * Data NEND NXD
+ * Data Merge Merge Data
+ * new NEND Merge Merge NEND
+ * NXD NXD NXD NXD
+ *
+ */
+/* XXX: this code calls nlookup, which can create namebuf's. if this code
+ * has to exit with a fatal error, it should scan from the new np upward
+ * and for each node which has no children and no data it should remove
+ * the namebuf. design notes: (1) there's no harm in doing this even if
+ * success occurred; (2) stopping on the first nonremovable np is optimal;
+ * the code for removal should be taken out of remove_zone() and made
+ * general enough for this use, and for remove_zone()'s continued use.
+ * vix, 21jul94
+ */
+int
+db_update(name, odp, newdp, flags, htp)
+ char name[];
+ struct databuf *odp, *newdp;
+ int flags;
+ struct hashbuf *htp;
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np;
+ int zn, isHintNS;
+ char *fname;
+
+ dprintf(3, (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":"" ));
+ np = nlookup(name, &htp, &fname, newdp != NULL);
+ if (np == NULL || fname != name)
+ return (NONAME);
+
+ /* don't let nonauthoritative updates write in authority zones */
+ if (newdp && (flags & DB_NOTAUTH) &&
+ (zn = findMyZone(np, newdp->d_class)) != DB_Z_CACHE) {
+ int foundRR = 0;
+
+ /* don't generate the warning if we've done so recently or
+ * if the update would have been harmless (identical data).
+ */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!db_cmp(dp, newdp)) {
+ foundRR++;
+ break;
+ }
+ }
+ if (!foundRR &&
+ !haveComplained((char*)from_addr.sin_addr.s_addr,
+ (char*)dhash((u_char*)name, strlen(name))))
+ syslog(LOG_NOTICE,
+ "[%s].%d attempted update to auth zone \"%s\" (%s)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ zones[zn].z_origin,
+ name);
+ return (AUTH);
+ }
+
+ /* some special checks for root NS' A RR's */
+ isHintNS = isRefByNS(name, fcachetab);
+ if (newdp && isHintNS && newdp->d_type == T_A) {
+ /* obviously bogus addresses die here */
+ if (
+#ifdef NCACHE
+ (!newdp->d_rcode) &&
+#endif
+ (((struct in_addr *)newdp->d_data)->s_addr == INADDR_ANY))
+ {
+ syslog(LOG_INFO, "bogus (0.0.0.0) root A RR received");
+ return (AUTH);
+ }
+ /* upgrade credibility of additional data for rootsrv addrs */
+ if (newdp->d_cred == DB_C_ADDITIONAL) {
+ dprintf(3, (ddt,
+ "upgrading credibility for A RR (%s)\n",
+ name));
+ /* XXX: should copy NS RR's, but we really just want
+ * to prevent deprecation later so this will do.
+ */
+ newdp->d_cred = DB_C_ANSWER;
+ newdp->d_clev = 0;
+ }
+ }
+
+ /* Reflect certain updates in hint cache also... */
+ /* Don't stick data we are authoritative for in hints. */
+ if (!(flags & DB_NOHINTS) &&
+ (odp != NULL) &&
+ (htp != fcachetab) &&
+ (odp->d_zone <= 0) &&
+ !(odp->d_flags & DB_F_HINT) &&
+#ifdef NCACHE
+ (!newdp || !newdp->d_rcode) &&
+#endif
+ ((name[0] == '\0' && odp->d_type == T_NS) ||
+ (odp->d_type == T_A && isHintNS)
+ )
+ )
+ {
+ dprintf(3, (ddt, "db_update: hint '%s' %d\n",
+ name, odp->d_ttl));
+ 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;
+ dp->d_cred = DB_C_CACHE;
+ dp->d_clev = 0;
+ if (db_update(name,
+ dp, dp,
+ (flags|DB_NOHINTS),
+ fcachetab)
+ != OK) {
+ dprintf(3, (ddt, "db_update: hint %x freed\n", dp));
+ (void) free((char *)dp);
+ }
+ }
+
+ if (odp != NULL) {
+ int foundRR = 0;
+
+ pdp = NULL;
+ for (dp = np->n_data; dp != NULL; ) {
+ if (!match(dp, odp->d_class, odp->d_type)) {
+ /* {class,type} doesn't match. these are
+ * the aggregation cases.
+ */
+ if ((dp->d_type == T_CNAME ||
+ odp->d_type == T_CNAME) &&
+ odp->d_class == dp->d_class &&
+ odp->d_mark == dp->d_mark &&
+#ifdef NCACHE
+ /* neither the odp nor the new dp are
+ * negatively cached records...
+ */
+ !dp->d_rcode &&
+ !odp->d_rcode &&
+#endif /*NCACHE*/
+ zones[odp->d_zone].z_type != Z_CACHE) {
+ syslog(LOG_ERR,
+ "%s has CNAME and other data (illegal)\n",
+ name);
+ dprintf(1, (ddt,
+ "db_update: %s: CNAME and more (%d, %d)\n",
+ name, odp->d_type,
+ dp->d_type));
+ goto skip;
+ }
+ if (!newdp || newdp->d_class != dp->d_class)
+ goto skip;
+
+ /* XXX:
+ * The next three clauses do not deal
+ * correctly with glue records. mpa.
+ */
+
+ /* if the new data is authorative
+ * remove any data for this domain with
+ * the same class that isn't as credable
+ */
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred > dp->d_cred)
+ /* better credibility and the old datum
+ * was not from a zone file. remove
+ * the old datum.
+ */
+ goto delete;
+
+ /* if we have authoritative data for a
+ * node, don't add in other data.
+ */
+ if (dp->d_cred == DB_C_ZONE &&
+ newdp->d_cred < dp->d_cred)
+ return (AUTH);
+
+ /* if the new data is authoritative but
+ * but isn't as credible, reject it.
+ */
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred == dp->d_cred &&
+ newdp->d_clev < dp->d_clev)
+ return (AUTH);
+#ifdef NCACHE
+ /* process NXDOMAIN */
+ /* policy */
+ if (newdp->d_rcode == NXDOMAIN) {
+ if (dp->d_cred < DB_C_AUTH)
+ goto delete;
+ else
+ return (DATAEXISTS);
+ }
+
+ if (dp->d_rcode == NXDOMAIN)
+ goto delete;
+
+ /* process NOERROR_NODATA */
+ /* NO PROCESSING REQUIRED */
+#endif /*NCACHE*/
+ goto skip;
+ } /*if {class,type} did not match*/
+
+ /* {type,class} did match. this is the replace case.
+ */
+ dprintf(5, (ddt,
+ "db_update: flags = %#x, sizes = %d, %d (cmp %d)\n",
+ flags, odp->d_size, dp->d_size,
+ db_cmp(dp, odp)));
+ if (newdp) {
+ dprintf(4, (ddt,
+ "credibility for %s is %d(%d) from [%s].%d, is %d(%d) in cache\n",
+ *name? name : ".",
+ newdp->d_cred,
+ newdp->d_clev,
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ dp->d_cred,
+ dp->d_clev));
+ if (newdp->d_cred > dp->d_cred ||
+ (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_clev > dp->d_clev)) {
+ /* better credibility and the old datum
+ * was not from a zone file. remove
+ * the old datum.
+ */
+ goto delete;
+ }
+ if (newdp->d_cred < dp->d_cred) {
+ /* credibility is worse. ignore it. */
+ return (AUTH);
+ }
+ if (newdp->d_cred == DB_C_ZONE &&
+ newdp->d_cred == dp->d_cred &&
+ newdp->d_clev < dp->d_clev)
+ return (AUTH);
+
+ /* credibility is the same.
+ * let it aggregate in the normal way.
+ */
+#ifdef NCACHE
+ /*
+ * if the new or old RR is -ve, delete old.
+ */
+ if (dp->d_rcode || newdp->d_rcode) {
+ /* XXX: how can a zone rr be neg? */
+ if (dp->d_cred != DB_C_ZONE)
+ goto delete;
+ else
+ return (DATAEXISTS);
+ }
+#endif
+ /*
+ * Some RR types should not be aggregated.
+ */
+ if (dp->d_type == T_SOA)
+ goto delete;
+ if (dp->d_type == T_WKS &&
+ !bcmp(dp->d_data, newdp->d_data, INT16SZ))
+ goto delete;
+ }
+ 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;
+ dprintf(4, (ddt,
+ "db_update: cache entry now in auth zone\n"
+ ));
+ return (DATAEXISTS);
+ }
+ fixttl(odp);
+ if (odp->d_ttl > dp->d_ttl)
+ dp->d_ttl = odp->d_ttl;
+ dprintf(3, (ddt,
+ "db_update: new ttl %d, +%d\n",
+ dp->d_ttl,
+ dp->d_ttl - tt.tv_sec));
+ }
+ 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) {
+ 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);
+ /* XXX: empty nodes bypass credibility checks above; should check
+ * response source address here if flags&NOTAUTH.
+ */
+ fixttl(newdp);
+ dprintf(3, (ddt, "db_update: adding%s %x\n",
+ (newdp->d_flags&DB_F_HINT) ? " hint":"", newdp));
+#ifdef INVQ
+ if (!(newdp->d_flags & DB_F_HINT))
+ addinv(np, newdp); /* modify inverse query tables */
+#endif
+
+#ifdef STATS
+ if (!newdp->d_zone && !(newdp->d_flags & DB_F_HINT))
+ newdp->d_ns = nameserFind(from_addr.sin_addr, NS_F_INSERT);
+#endif
+
+ /* Add to end of list, generally preserving order */
+ newdp->d_next = NULL;
+ if ((dp = np->n_data) == NULL) {
+#ifdef DATUMREFCNT
+ newdp->d_rcnt = 1;
+#endif
+ np->n_data = newdp;
+ return (OK);
+ }
+ 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);
+#ifdef DATUMREFCNT
+ newdp->d_rcnt = 1;
+#endif
+ dp->d_next = newdp;
+ return (OK);
+}
+
+static void
+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;
+}
+
+/*
+ * Compare type, class and data from databufs for equivalence.
+ * Must be case insensitive for some domain names.
+ * Return 0 if equivalent, nonzero otherwise.
+ */
+static int
+db_cmp(dp1, dp2)
+ register struct databuf *dp1, *dp2;
+{
+ register u_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 */
+#ifdef NCACHE
+ if (dp1->d_rcode && dp2->d_rcode)
+ return ((dp1->d_rcode == dp1->d_rcode)?0:1);
+ if (dp1->d_rcode || dp2->d_rcode)
+ return (1);
+#endif
+
+ switch (dp1->d_type) {
+
+ case T_A:
+ case T_UID:
+ case T_GID:
+ case T_WKS:
+ case T_NULL:
+ case T_NSAP:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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((char *)dp1->d_data, (char *)dp2->d_data));
+
+ case T_HINFO:
+ case T_ISDN:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ len = *cp1;
+ if (strncasecmp((char *)++cp1, (char *)++cp2, len))
+ return (1);
+ cp1 += len;
+ cp2 += len;
+ len = *cp1;
+ return (strncasecmp((char *)++cp1, (char *)++cp2, len));
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ if (strcasecmp((char *)dp1->d_data, (char *)dp2->d_data))
+ return (1);
+ cp1 = dp1->d_data + strlen((char *)dp1->d_data) + 1;
+ cp2 = dp2->d_data + strlen((char *)dp2->d_data) + 1;
+ if (dp1->d_type != T_SOA)
+ return (strcasecmp((char *)cp1, (char *)cp2));
+ if (strcasecmp((char *)cp1, (char *)cp2))
+ return (1);
+ cp1 += strlen((char *)cp1) + 1;
+ cp2 += strlen((char *)cp2) + 1;
+ return (bcmp(cp1, cp2, INT32SZ * 5));
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ cp1 = dp1->d_data;
+ cp2 = dp2->d_data;
+ if (*cp1++ != *cp2++ || *cp1++ != *cp2++) /* cmp prio */
+ return (1);
+ return (strcasecmp((char *)cp1, (char *)cp2));
+
+ case T_TXT:
+ case T_X25:
+ 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/dmalloc.c b/usr.sbin/named/dmalloc.c
new file mode 100644
index 0000000..f30dec4
--- /dev/null
+++ b/usr.sbin/named/dmalloc.c
@@ -0,0 +1,310 @@
+/* dmalloc - debugging layer on top of malloc
+ * vix 25mar92 [fixed bug in round-up calcs in alloc()]
+ * vix 24mar92 [added size calcs, improved printout]
+ * vix 22mar92 [original work]
+ *
+ * $Id: dmalloc.c,v 1.1.1.1 1994/09/22 19:46:14 pst Exp $
+ */
+
+/*
+ * ++Copyright++ 1993
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef DMALLOC
+
+#define TRUE 1
+#define FALSE 0
+typedef unsigned bool;
+
+#define MAX_MEMORY 65536 /* must fit in typeof(datum.size) */
+#define MAX_CALLERS 256 /* must be **2 */
+
+typedef struct caller {
+ struct caller *next;
+ struct filenam *file;
+ struct calltab *frees;
+ unsigned line;
+ unsigned calls;
+ unsigned blocks;
+ unsigned bytes;
+} caller;
+
+typedef struct filenam {
+ struct filenam *next;
+ char *name;
+} filenam;
+
+typedef struct calltab {
+ struct caller *callers[MAX_CALLERS];
+} calltab;
+
+typedef struct datum {
+ unsigned size; /* size of malloc'd item */
+ unsigned caller; /* offset into memory[] */
+ /* user data follows */
+} datum;
+
+static char memory[MAX_MEMORY];
+static char *nextmem = memory;
+static char *alloc(size) unsigned size; {
+ char *thismem = nextmem;
+ int oddness = (size % sizeof(char*));
+ if (oddness)
+ size += (sizeof(char*) - oddness);
+ nextmem += size;
+ if (nextmem >= &memory[MAX_MEMORY]) {
+ fprintf(stderr, "dmalloc.alloc: out of mem\n");
+ kill(0, SIGBUS);
+ }
+ return thismem;
+ }
+
+static filenam *Files;
+static calltab Callers;
+
+/*--------------------------------------------------- imports
+ */
+
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+
+char *malloc(), *calloc(), *realloc();
+
+#if defined(sun)
+int free();
+#else
+void free();
+#endif
+
+/*--------------------------------------------------- private
+ */
+
+#define STR_EQ(l,r) (((l)[0] == (r)[0]) && !strcmp(l, r))
+
+static filenam *
+findFile(file, addflag)
+ char *file;
+ bool addflag;
+{
+ filenam *f;
+
+ for (f = Files; f; f = f->next)
+ if (STR_EQ(file, f->name))
+ return f;
+ if (!addflag)
+ return NULL;
+ f = (filenam*) alloc(sizeof(filenam));
+ f->next = Files;
+ Files = f;
+ f->name = alloc(strlen(file) + 1);
+ strcpy(f->name, file);
+ return f;
+}
+
+static caller *
+findCaller(ctab, file, line, addflag)
+ calltab *ctab;
+ char *file;
+ unsigned line;
+ bool addflag;
+{
+ unsigned hash = line & (MAX_CALLERS - 1);
+ caller *c;
+
+ for (c = ctab->callers[hash]; c; c = c->next)
+ if ((c->line == line) && STR_EQ(c->file->name, file))
+ return c;
+ if (!addflag)
+ return NULL;
+ c = (caller*) alloc(sizeof(caller));
+ c->next = ctab->callers[hash];
+ c->file = findFile(file, TRUE);
+ c->line = line;
+ c->calls = 0;
+ c->frees = (calltab *) alloc(sizeof(calltab));
+ ctab->callers[hash] = c;
+ return c;
+}
+
+/*--------------------------------------------------- public
+ */
+
+char *
+dmalloc(file, line, size)
+ char *file;
+ unsigned line;
+ unsigned size;
+{
+ caller *c;
+ datum *d;
+
+ c = findCaller(&Callers, file, line, TRUE);
+ d = (datum *) malloc(sizeof(datum) + size);
+ d->size = size;
+ d->caller = ((char *)c) - memory;
+ c->calls++;
+ c->blocks++;
+ c->bytes += size;
+ return (char *) (d+1);
+}
+
+void
+dfree(file, line, ptr)
+ char *file;
+ unsigned line;
+ char *ptr;
+{
+ caller *c, *a;
+ datum *d;
+
+ d = (datum *) ptr; d--;
+ a = (caller *) (memory + d->caller);
+ a->bytes -= d->size;
+ a->blocks--;
+ c = findCaller(a->frees, file, line, TRUE);
+ c->calls++;
+ free((char*) d);
+}
+
+char *
+dcalloc(file, line, nelems, elsize)
+ char *file;
+ unsigned line;
+ unsigned nelems, elsize;
+{
+ unsigned size = (nelems * elsize);
+ char *ptr;
+
+ ptr = dmalloc(file, line, size);
+ bzero(ptr, size);
+ return ptr;
+}
+
+char *
+drealloc(file, line, ptr, size)
+ char *file;
+ unsigned line;
+ char *ptr;
+ unsigned size;
+{
+ caller *c, *a;
+ datum *d;
+
+ d = (datum *) ptr; d--;
+ /* fix up stats from allocation */
+ a = (caller *) (memory + d->caller);
+ a->bytes -= d->size;
+ a->blocks--;
+ /* we are a "freer" of this allocation */
+ c = findCaller(a->frees, file, line, TRUE);
+ c->calls++;
+ /* get new allocation and stat it */
+ c = findCaller(&Callers, file, line, TRUE);
+ d = (datum *) realloc((char *) d, sizeof(datum) + size);
+ d->size = size;
+ d->caller = ((char *)c) - memory;
+ c->calls++;
+ c->blocks++;
+ c->bytes += size;
+ return (char *) (d+1);
+}
+
+static void
+dmalloccallers(outf, prefix, ctab)
+ FILE *outf;
+ char *prefix;
+ calltab *ctab;
+{
+ /* this bizarre logic is to print all of a file's entries together */
+ filenam *f;
+
+ for (f = Files; f; f = f->next) {
+ int i;
+
+ for (i = MAX_CALLERS-1; i >= 0; i--) {
+ caller *c;
+
+ for (c = ctab->callers[i]; c; c = c->next) {
+ if (f != c->file)
+ continue;
+ fprintf(outf, "%s\"%s\":%u calls=%u",
+ prefix, c->file->name, c->line,
+ c->calls);
+ if (c->blocks || c->bytes)
+ fprintf(outf, " blocks=%u bytes=%u",
+ c->blocks, c->bytes);
+ fputc('\n', outf);
+ if (c->frees)
+ dmalloccallers(outf,
+ "\t\t", c->frees);
+ }
+ }
+ }
+}
+
+void
+dmallocstats(outf)
+ FILE *outf;
+{
+ fprintf(outf, "dallocstats [ private mem used=%u, avail=%u ]\n",
+ nextmem - memory, &memory[MAX_MEMORY] - nextmem);
+ dmalloccallers(outf, "\t", &Callers);
+}
+
+#endif /*DMALLOC*/
diff --git a/usr.sbin/named/dmalloc.h b/usr.sbin/named/dmalloc.h
new file mode 100644
index 0000000..54e68f9
--- /dev/null
+++ b/usr.sbin/named/dmalloc.h
@@ -0,0 +1,68 @@
+/* dmalloc - debugging layer on top of malloc
+ * vix 22mar92 [written]
+ *
+ * $Id: dmalloc.h,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $
+ */
+
+/*
+ * ++Copyright++
+ * -
+ * Copyright (c)
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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--
+ */
+
+#define malloc(s) dmalloc(__FILE__, __LINE__, s)
+#define free(p) dfree(__FILE__, __LINE__, p)
+#define calloc(n, s) dcalloc(__FILE__, __LINE__, n, s)
+#define realloc(p, s) drealloc(__FILE__, __LINE__, p, s)
+
+char *dmalloc(), *dcalloc(), *drealloc();
+void dfree(), dmallocstats();
diff --git a/usr.sbin/named/named.8 b/usr.sbin/named/named.8
new file mode 100644
index 0000000..9ab4e49
--- /dev/null
+++ b/usr.sbin/named/named.8
@@ -0,0 +1,378 @@
+.\" ++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--
+.\"
+.\" @(#)named.8 6.6 (Berkeley) 2/14/89
+.\"
+.TH @INDOT_U@NAMED @SYS_OPS_EXT_U@ "April 17, 1993"
+.UC 4
+.SH NAME
+@INDOT@named \- Internet domain name server
+.SH SYNOPSIS
+.B @INDOT@named
+[
+.B \-d
+.I debuglevel
+] [
+.B \-p
+.I port#
+] [{\-b}
+.I bootfile
+] [
+.B \-q
+] [
+.B \-r
+]
+.SH DESCRIPTION
+.I Named
+is the Internet domain name server.
+See RFC's 1033, 1034, and 1035 for more information on the Internet
+name-domain system. Without any arguments,
+.I named
+will read the default boot file
+.IR /etc/named.boot ,
+read any initial data and listen for queries.
+.PP
+Options are:
+.TP
+.B \-d
+Print debugging information.
+A number after the ``d'' determines the level of
+messages printed.
+.TP
+.B \-p
+Use a different port number. The default is the standard port number
+as returned by getservbyname(@LIB_NETWORK_EXT@) for service ``domain''.
+.TP
+.B \-b
+Use an alternate boot file. This is optional and allows you to
+specify a file with a leading dash.
+.TP
+.B \-q
+Trace all incoming queries if \fInamed\fP has been compiled with
+\fIQRYLOG\fP defined.
+.TP
+.B \-r
+Turns recursion off in the server. Answers can come only from local
+(primary or secondary) zones. This can be used on root servers.
+.PP
+Any additional argument is taken as the name of the boot file.
+If multiple boot files are specified, only the last is used.
+.PP
+The boot file contains information about where the name server is to get
+its initial data.
+Lines in the boot file cannot be continued on subsequent lines.
+The following is a small example:
+.in +2m
+.nf
+
+;
+; boot file for name server
+;
+directory /usr/local/adm/named
+
+.ta \w'forwarders\ 'u +\w'6.32.128.IN-ADDR.ARPA\ 'u +\w'128.32.137.8 128.32.137.3\ 'u
+; 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
+
+.DT
+.fi
+.in
+The ``directory'' line causes the server to change its working directory to
+the directory specified. This can be important for the correct processing
+of \s-1$INCLUDE\s+1 files in primary zone files.
+.LP
+The ``cache'' line specifies that data in ``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 ``hints'' to find the current root servers. The file ``root.cache'' is
+in the same format as ``berkeley.edu.zone''. There can be more than one
+``cache'' file specified. The ``root.cache'' file should be retrieved
+periodically from \s-1FTP.RS.INTERNIC.NET\s+1 since it contains a list of
+root servers, and this list changes periodically.
+.LP
+The first example ``primary'' line states that the file
+``berkeley.edu.zone'' contains authoritative data for the ``Berkeley.EDU''
+zone. The file ``berkeley.edu.zone'' contains data in the master file
+format described in RFC883. All domain names are relative to the origin, in
+this case, ``Berkeley.EDU'' (see below for a more detailed description).
+The second ``primary'' line states that the file ``ucbhosts.rev'' contains
+authoritative data for the domain ``32.128.IN-ADDR.ARPA,'' which is used to
+translate addresses in network 128.32 to hostnames. Each master file should
+begin with an SOA record for the zone (see below).
+.LP
+The first example ``secondary'' line specifies that all authoritative data
+under ``CC.Berkeley.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
+transferred 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. If no file name is given, a temporary file will be used, and will
+be deleted after each successful zone transfer. This is not recommended
+since it is a needless waste of bandwidth. The second example ``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.
+.LP
+The ``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.
+.LP
+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.
+.LP
+The ``sortlist'' line can be used to indicate networks that are to be
+preferred over other 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.
+.LP
+The ``xfrnets'' directive (not shown) can be used to implement primative
+access control. If this directive is given, then your name server will
+only answer zone transfer requests from hosts which are on networks listed
+in your ``xfrnets'' directives. This directive may also be given as
+``tcplist'' for compatibility with older, interrim servers.
+.LP
+The ``include'' directive (not shown) can be used to process the contents
+of some other file as though they appeared in place of the ``include''
+directive. This is useful if you have a lot of zones or if you have
+logical groupings of zones which are maintained by different people.
+The ``include'' directive takes one argument, that being the name of the
+file whose contents are to be included. No quotes are necessary around
+the file name.
+.LP
+The ``bogusns'' directive (not shown) tells \s-1BIND\s+1 that no queries
+are to be sent to the specified name server addresses (which are specified
+as dotted quads, not as domain names). This is useful when you know that
+some popular server has bad data in a zone or cache, and you want to avoid
+contamination while the problem is being fixed.
+.LP
+The ``max-fetch'' directive (not shown) can be used to override the default
+limit (which is 10) to the number of named-xfer subprocesses which \s-1BIND\s+1
+can spawn at any one time.
+.PP
+The master file consists of control information and a list of resource
+records for objects in the zone of the forms:
+.RS
+.nf
+
+$INCLUDE <filename> <opt_domain>
+$ORIGIN <domain>
+<domain> <opt_ttl> <opt_class> <type> <resource_record_data>
+
+.fi
+.RE
+where
+.I domain
+is "." for root, "@" for the current origin, or a standard domain
+name. If
+.I domain
+is a standard domain name that does not end with ``.'', the current origin
+is appended to the domain. Domain names ending with ``.'' are
+unmodified.
+The
+.I opt_domain
+field is used to define an origin for the data in an included file.
+It is equivalent to placing a $ORIGIN statement before the first
+line of the included file. The field is optional.
+Neither the
+.I opt_domain
+field nor $ORIGIN statements in the included file modify the current origin
+for this file.
+The
+.I 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
+.I opt_class
+field is the object address type; currently only one type is supported,
+.BR IN ,
+for objects connected to the DARPA Internet.
+The
+.I type
+field contains one of the following tokens; the data expected in the
+.I resource_record_data
+field is in parentheses.
+.TP "\w'MINFO 'u"
+A
+a host address (dotted quad)
+.IP NS
+an authoritative name server (domain)
+.IP MX
+a mail exchanger (domain), preceded by a preference value (0..32767),
+with lower numeric values representing higher logical preferences.
+.IP CNAME
+the canonical name for an alias (domain)
+.IP 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 RFC883)).
+.IP NULL
+a null resource record (no format or data)
+.IP RP
+a Responsible Person for some domain name (mailbox, TXT-referral)
+.IP PTR
+a domain name pointer (domain)
+.IP HINFO
+host information (cpu_type OS_type)
+.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
+Note that there are other resource record types, not shown here. You should
+consult the \s-1BIND\s+1 Operations Guide (``\s-1BOG\s+1'') for the complete
+list. Some resource record types may have been standardized in newer RFC's
+but not yet implemented in this version of \s-1BIND\s+1.
+.PP
+Each master zone file should begin with an SOA record for the zone.
+An example SOA record is as follows:
+.LP
+.nf
+@ IN SOA ucbvax.Berkeley.EDU. rwh.ucbvax.Berkeley.EDU. (
+ 1989020501 ; serial
+ 10800 ; refresh
+ 3600 ; retry
+ 3600000 ; expire
+ 86400 ) ; minimum
+.fi
+.LP
+The SOA specifies a serial number, which should be changed each time the
+master file is changed. Note that the serial number can be given as a
+dotted number, but this is a \fIvery\fP unwise thing to do since the
+translation to normal integers is via concatenation rather than
+multiplication and addition. You can spell out the year, month, day of
+month, and 0..99 version number and still fit inside the unsigned 32-bit
+size of this field. It's true that we will have to rethink this strategy in
+the year 4294 (Greg.) but we're not worried about it. 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.
+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 (``\s-1TTL\s+1'') 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.
+.sp
+The following signals have the specified effect when sent to the
+server process using the
+.IR kill (@CMD_EXT@)
+command.
+.IP SIGHUP
+Causes server to read named.boot and reload database. If the server
+is built with the FORCED_RELOAD compile-time option, then SIGHUP will
+also cause the server to check the serial number on all secondary zones.
+Normally the serial numbers are only checked at the SOA-specified intervals.
+.IP SIGINT
+Dumps current data base and cache to /var/tmp/named_dump.db
+.IP SIGIOT
+Dumps statistics data into /var/tmp/named.stats if the server is
+compiled -DSTATS. Statistics data is appended to the file.
+.IP SIGSYS
+Dumps the profiling data in /var/tmp if the server is compiled
+with profiling (server forks, chdirs and exits).
+.IP SIGTERM
+Dumps the primary and secondary database files.
+Used to save modified data on shutdown if the
+server is compiled with dynamic updating enabled.
+.IP SIGUSR1
+Turns on debugging; each SIGUSR1 increments debug level.
+(SIGEMT on older systems without SIGUSR1)
+.IP SIGUSR2
+Turns off debugging completely.
+(SIGFPE on older systems without SIGUSR2)
+.IP SIGWINCH
+Toggles logging of all incoming queries via syslog(@SYS_OPS_EXT@)
+(requires server to have been built with the QRYLOG option).
+.SH FILES
+.nf
+.ta \w'/var/tmp/named_dump.db 'u
+/etc/named.boot name server configuration boot file
+/etc/named.pid the process id (/var/run/named.pid on newer systems)
+/var/tmp/named.run debug output
+/var/tmp/named_dump.db dump of the name server database
+/var/tmp/named.stats nameserver statistics data
+.fi
+.SH "SEE ALSO"
+kill(@CMD_EXT@), gethostbyname(@LIB_NETWORK_EXT@), signal(@SYSCALL_EXT@),
+resolver(@LIB_NETWORK_EXT@), resolver(@FORMAT_EXT@), hostname(@DESC_EXT@),
+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/named.h b/usr.sbin/named/named.h
new file mode 100644
index 0000000..e3e795d
--- /dev/null
+++ b/usr.sbin/named/named.h
@@ -0,0 +1,19 @@
+/* named.h - include the local definitions in the right order
+ * vix 28aug93 [original]
+ *
+ * $Id: named.h,v 1.1 1993/09/08 04:57:40 vixie Exp $
+ */
+
+#include "options.h"
+#include "portability.h"
+
+#include "pathnames.h"
+
+#include "ns_defs.h"
+#include "db_defs.h"
+
+#include "ns_glob.h"
+#include "db_glob.h"
+
+#include "ns_func.h"
+#include "db_func.h"
diff --git a/usr.sbin/named/ns_defs.h b/usr.sbin/named/ns_defs.h
new file mode 100644
index 0000000..bb9f18f
--- /dev/null
+++ b/usr.sbin/named/ns_defs.h
@@ -0,0 +1,368 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_defs.h,v 1.12 1994/07/23 23:23:56 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Global definitions for the name server.
+ */
+
+/*
+ * Effort has been expended here to make all structure members 32 bits or
+ * larger land on 32-bit boundaries; smaller structure members have been
+ * deliberately shuffled and smaller integer sizes chosen where possible
+ * to make sure this happens. This is all meant to avoid structure member
+ * padding which can cost a _lot_ of memory when you have hundreds of
+ * thousands of entries in your cache.
+ */
+
+/*
+ * 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 ([0..255]) */
+#define RETRYBASE 4 /* base time between retries */
+#define MAXCLASS 255 /* XXX - may belong elsewhere */
+#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 */
+#define MAXQSERIAL 4 /* max # of outstanding QSERIAL's */
+ /* (prevent "recursive" loops) */
+#define INIT_REFRESH 600 /* retry time for initial secondary */
+ /* contact (10 minutes) */
+#define NADDRECS 20 /* max addt'l rr's per resp */
+
+#define XFER_TIMER 120 /* named-xfer's connect timeout */
+#define MAX_XFER_TIME 60*60*2 /* max seconds for an xfer */
+#define XFER_TIME_FUDGE 10 /* MAX_XFER_TIME fudge */
+#define MAX_XFERS_RUNNING 10 /* default max value of xfers_running */
+#define MAX_XFERS_PERNS 2 /* max # of xfers per peer nameserver */
+
+#define ALPHA 0.7 /* How much to preserve 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 */
+
+ /* sequence-space arithmetic */
+#define SEQ_GT(a,b) ((int32_t)((a)-(b)) > 0)
+
+/* these fields are ordered to maintain word-alignment;
+ * be careful about changing them.
+ */
+struct zoneinfo {
+ 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_int32_t z_refresh; /* refresh interval */
+ u_int32_t z_retry; /* refresh retry interval */
+ u_int32_t z_expire; /* expiration time for cached info */
+ u_int32_t z_minimum; /* minimum TTL value */
+ u_int32_t z_serial; /* changes if zone modified */
+ char *z_source; /* source location of data */
+ time_t z_ftime; /* modification time of source file */
+ struct in_addr z_xaddr; /* override server for next xfer */
+ struct in_addr z_addr[NSMAX]; /* list of master servers for zone */
+ u_char z_addrcnt; /* number of entries in z_addr[] */
+ u_char z_type; /* type of zone; see below */
+ u_int16_t z_flags; /* state bits; see below */
+ pid_t z_xferpid; /* xfer child pid */
+ int z_class; /* class of zone */
+#ifdef SECURE_ZONES
+ struct netinfo *secure_nets; /* list of secure networks for zone */
+#endif
+};
+
+ /* zone types (z_type) */
+#define Z_NIL 0 /* zone slot not in use */
+#define Z_PRIMARY 1
+#define Z_SECONDARY 2
+#define Z_CACHE 3
+#define Z_STUB 4
+
+ /* zone state bits (16 bits) */
+#define Z_AUTH 0x0001 /* zone is authoritative */
+#define Z_NEED_XFER 0x0002 /* waiting to do xfer */
+#define Z_XFER_RUNNING 0x0004 /* asynch. xfer is running */
+#define Z_NEED_RELOAD 0x0008 /* waiting to do reload */
+#define Z_SYSLOGGED 0x0010 /* have logged timeout */
+#define Z_QSERIAL 0x0020 /* sysquery()'ing for serial number */
+#define Z_FOUND 0x0040 /* found in boot file when reloading */
+#define Z_INCLUDE 0x0080 /* set if include used in file */
+#define Z_DB_BAD 0x0100 /* errors when loading file */
+#define Z_TMP_FILE 0x0200 /* backup file for xfer is temporary */
+#ifdef ALLOW_UPDATES
+#define Z_DYNAMIC 0x0400 /* allow dynamic updates */
+#define Z_DYNADDONLY 0x0800 /* dynamic mode: add new data only */
+#define Z_CHANGED 0x1000 /* zone has changed */
+#endif /* ALLOW_UPDATES */
+
+ /* named_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 */
+
+#include <sys/time.h>
+
+/* XXX - "struct qserv" is deprecated in favor of "struct nameser" */
+struct qserv {
+ struct sockaddr_in
+ ns_addr; /* address of NS */
+ 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 */
+};
+
+/*
+ * Structure for recording info on forwarded or generated queries.
+ */
+struct qinfo {
+ u_int16_t q_id; /* id of query */
+ u_int16_t q_nsid; /* id of forwarded query */
+ struct sockaddr_in
+ q_from; /* requestor's address */
+ u_char *q_msg, /* the message */
+ *q_cmsg; /* the cname message */
+ int16_t q_msglen, /* len of message */
+ q_cmsglen; /* len of cname message */
+ int16_t q_dfd; /* UDP file descriptor */
+ struct fwdinfo *q_fwd; /* last forwarder used */
+ time_t q_time; /* time to retry */
+ time_t q_expire; /* time to expire */
+ struct qinfo *q_next; /* rexmit list (sorted by time) */
+ struct qinfo *q_link; /* storage list (random order) */
+ struct databuf *q_usedns[NSMAX]; /* databuf for NS that we've tried */
+ struct qserv q_addr[NSMAX]; /* addresses of NS's */
+#ifdef notyet
+ struct nameser *q_ns[NSMAX]; /* name servers */
+#endif
+ u_char q_naddr; /* number of addr's in q_addr */
+ u_char q_curaddr; /* last addr sent to */
+ u_char q_nusedns; /* number of elements in q_usedns[] */
+ u_int8_t q_flags; /* see below */
+ int16_t q_cname; /* # of cnames found */
+ int16_t q_nqueries; /* # of queries required */
+ struct qstream *q_stream; /* TCP stream, null if UDP */
+ struct zoneinfo *q_zquery; /* Zone query is about (Q_ZSERIAL) */
+#ifdef LAME_DELEGATION
+ char q_domain[MAXDNAME]; /* domain for servers we are querying */
+#endif /* LAME_DELEGATION */
+};
+
+ /* q_flags bits (8 bits) */
+#define Q_SYSTEM 0x01 /* is a system query */
+#define Q_PRIMING 0x02 /* generated during priming phase */
+#define Q_ZSERIAL 0x04 /* getting zone serial for xfer test */
+
+#define Q_NEXTADDR(qp,n) \
+ (((qp)->q_fwd == (struct fwdinfo *)0) ? \
+ &(qp)->q_addr[n].ns_addr : &(qp)->q_fwd->fwdaddr)
+
+#define RETRY_TIMEOUT 45
+#define QINFO_NULL ((struct qinfo *)0)
+
+/*
+ * 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 */
+ u_char *s_buf; /* buffer of received data */
+ u_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_int32_t s_time; /* time stamp of last transaction */
+ int s_refcnt; /* number of outstanding queries */
+ u_int16_t s_tempsize; /* temporary for size from net */
+};
+#define QSTREAM_NULL ((struct qstream *)0)
+
+struct qdatagram {
+ int dq_dfd; /* datagram file descriptor */
+ time_t dq_gen; /* generation number */
+ struct qdatagram
+ *dq_next; /* next datagram */
+ struct in_addr dq_addr; /* interface address */
+};
+#define QDATAGRAM_NULL ((struct qdatagram *)0)
+
+struct netinfo {
+ struct netinfo *next;
+ u_int32_t addr;
+ u_int32_t mask;
+ struct in_addr my_addr;
+};
+
+#define ALLOW_NETS 0x0001
+#define ALLOW_HOSTS 0x0002
+#define ALLOW_ALL (ALLOW_NETS | ALLOW_HOSTS)
+
+struct fwdinfo {
+ struct fwdinfo *next;
+ struct sockaddr_in
+ fwdaddr;
+};
+
+enum nameserStats { nssRcvdQ, /* sent us a query */
+ nssRcvdR, /* sent us an answer */
+ nssRcvdIQ, /* sent us an inverse query */
+ nssRcvdNXD, /* sent us a negative response */
+ nssRcvdFwdQ, /* sent us a query we had to fwd */
+ nssRcvdFwdR, /* sent us a response we had to fwd */
+ nssRcvdDupQ, /* sent us a retry */
+ nssRcvdDupR, /* sent us an extra answer */
+ nssRcvdFail, /* sent us a SERVFAIL */
+ nssRcvdFErr, /* sent us a FORMERR */
+ nssRcvdErr, /* sent us some other error */
+ nssRcvdTCP, /* sent us a query using TCP */
+ nssRcvdAXFR, /* sent us an AXFR */
+ nssRcvdLDel, /* sent us a lame delegation */
+ nssRcvdOpts, /* sent us some IP options */
+ nssSentSysQ, /* sent them a sysquery */
+ nssSentAns, /* sent them an answer */
+ nssSentFwdQ, /* fwdd a query to them */
+ nssSentFwdR, /* fwdd a response to them */
+ nssSentDupQ, /* sent them a retry */
+ nssSentFail, /* sent them a SERVFAIL */
+ nssSentFErr, /* sent them a FORMERR */
+ nssSendtoErr, /* error in sendto(2) */
+ nssLast };
+
+struct nameser {
+ struct in_addr addr; /* key */
+ u_long stats[nssLast]; /* statistics */
+#ifdef notyet
+ u_int32_t rtt; /* round trip time */
+ /* XXX - need to add more stuff from "struct qserv", and use our rtt */
+ u_int16_t flags; /* see below */
+#endif
+ u_int8_t xfers; /* #/xfers running right now */
+};
+
+
+#ifdef NCACHE
+#define NOERROR_NODATA 6 /* only used internally by the server, used for
+ * -ve $ing non-existence of records. 6 is not
+ * a code used as yet anyway. anant@isi.edu
+ */
+#define NTTL 600 /* ttl for negative data: 10 minutes? */
+#endif /*NCACHE*/
+
+#define VQEXPIRY 900 /* a VQ entry expires in 15*60 = 900 seconds */
+
+#ifdef VALIDATE
+
+#define INVALID 0
+#define VALID_NO_CACHE 1
+#define VALID_CACHE 2
+#define MAXNAMECACHE 100
+#define MAXVQ 100 /* Max number of elements in TO_Validate queue */
+
+struct _nameaddr {
+ struct in_addr ns_addr;
+ char *nsname;
+};
+typedef struct _nameaddr NAMEADDR;
+
+struct _to_validate {
+ int16_t class; /* Name Class */
+ int16_t type; /* RR type */
+ char *data; /* RR data */
+ char *dname; /* Name */
+ time_t time; /* time at which inserted in queue */
+ struct _to_validate
+ *next,
+ *prev;
+};
+typedef struct _to_validate TO_Validate;
+
+#endif /*VALIDATE*/
+
+
+#ifdef DEBUG
+# define dprintf(lev, args) ((debug >= lev) && fprintf args)
+#else
+# define dprintf(lev, args)
+#endif
+
+
+#ifdef INIT
+ error "INIT already defined, check system include files"
+#endif
+#ifdef DECL
+ error "DECL already defined, check system include files"
+#endif
+
+#ifdef MAIN_PROGRAM
+#define INIT(x) = x
+#define DECL
+#else
+#define INIT(x)
+#define DECL extern
+#endif
diff --git a/usr.sbin/named/ns_forw.c b/usr.sbin/named/ns_forw.c
new file mode 100644
index 0000000..5745964
--- /dev/null
+++ b/usr.sbin/named/ns_forw.c
@@ -0,0 +1,909 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_forw.c 4.32 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_forw.c,v 4.9.1.17 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <syslog.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "named.h"
+
+/*
+ * 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 or if asked to do something
+ * dangerous, such as fwd to ourselves or fwd to the host that asked us.
+ *
+ * (no action is taken on errors and qpp is not filled in.)
+ */
+int
+ns_forw(nsp, msg, msglen, fp, qsp, dfd, qpp, dname, np)
+ struct databuf *nsp[];
+ u_char *msg;
+ int msglen;
+ struct sockaddr_in *fp;
+ struct qstream *qsp;
+ int dfd;
+ struct qinfo **qpp;
+ char *dname;
+ struct namebuf *np;
+{
+ register struct qinfo *qp;
+ struct sockaddr_in *nsa;
+ HEADER *hp;
+ u_int16_t id;
+ int n;
+
+ dprintf(3, (ddt, "ns_forw()\n"));
+
+ 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))) {
+ dprintf(3, (ddt,
+ "forw: dropped DUP id=%d\n", ntohs(id)));
+ nameserIncr(fp->sin_addr, nssRcvdDupQ);
+ return (FW_DUP);
+ }
+ }
+
+ qp = qnew();
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof qp->q_domain);
+#endif
+ qp->q_from = *fp; /* nslookup wants to know this */
+ if ((n = nslookup(nsp, qp, dname, "ns_forw")) < 0) {
+ dprintf(2, (ddt, "forw: nslookup reports danger\n"));
+ qfree(qp);
+ return (FW_SERVFAIL);
+ } else if (n == 0 && !(forward_only && fwdtab)) {
+ dprintf(2, (ddt, "forw: no nameservers found\n"));
+ 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;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ hp->id = qp->q_nsid = htons((u_int16_t)++nsid);
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ if ((qp->q_msg = (u_char *)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;
+ }
+
+#ifdef SLAVE_FORWARD
+ if (forward_only)
+ schedretry(qp, (time_t)slave_retry);
+ else
+#endif /* SLAVE_FORWARD */
+ schedretry(qp, qp->q_fwd ?(2*RETRYBASE) :retrytime(qp));
+
+ nsa = Q_NEXTADDR(qp, 0);
+ dprintf(1, (ddt,
+ "forw: forw -> [%s].%d ds=%d nsid=%d id=%d %dms retry %dsec\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[0].nsdata != NULL)
+ ? qp->q_addr[0].nsdata->d_nstime
+ : -1,
+ qp->q_time - tt.tv_sec));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (sendto(ds, msg, msglen, 0, (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "ns_forw: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(fp->sin_addr, nssRcvdFwdQ);
+ nameserIncr(nsa->sin_addr, nssSentFwdQ);
+ if (qpp)
+ *qpp = qp;
+ hp->rd = 1;
+ return (0);
+}
+
+/* struct qdatagram *
+ * aIsUs(addr)
+ * scan the datagramq (our list of interface addresses) for "addr"
+ * returns:
+ * pointer to qdatagram entry or NULL if no match is found
+ * notes:
+ * INADDR_ANY ([0.0.0.0]) is on the datagramq, so it's considered "us"
+ * author:
+ * Paul Vixie (DECWRL) April 1991
+ */
+struct qdatagram *
+aIsUs(addr)
+ struct in_addr addr;
+{
+ struct qdatagram *dqp;
+
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next) {
+ if (addr.s_addr == dqp->dq_addr.s_addr) {
+ return dqp;
+ }
+ }
+ return NULL;
+}
+
+/* haveComplained(tag1, tag2)
+ * check to see if we have complained about (tag1,tag2) recently
+ * (note that these are declared as pointers but are never deref'd)
+ * returns:
+ * boolean: have we complained recently?
+ * side-effects:
+ * outdated complaint records removed from our static list
+ * author:
+ * Paul Vixie (DECWRL) April 1991
+ */
+int
+haveComplained(tag1, tag2)
+ char *tag1, *tag2;
+{
+ struct complaint {
+ char *tag1, *tag2;
+ time_t expire;
+ struct complaint *next;
+ };
+ static struct complaint *List = NULL;
+ struct complaint *cur, *next, *prev;
+ int r = 0;
+
+ for (cur = List, prev = NULL; cur; prev = cur, cur = next) {
+ next = cur->next;
+ if (tt.tv_sec > cur->expire) {
+ if (prev)
+ prev->next = next;
+ else
+ List = next;
+ free((char*) cur);
+ cur = prev;
+ } else if ((tag1 == cur->tag1) && (tag2 == cur->tag2)) {
+ r++;
+ }
+ }
+ if (!r) {
+ cur = (struct complaint *)malloc(sizeof(struct complaint));
+ cur->tag1 = tag1;
+ cur->tag2 = tag2;
+ cur->expire = tt.tv_sec + INIT_REFRESH; /* "10 minutes" */
+ cur->next = NULL;
+ if (prev)
+ prev->next = cur;
+ else
+ List = cur;
+ }
+ return r;
+}
+
+/* void
+ * nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
+ * Issue a complaint about a dangerous situation found by nslookup().
+ * params:
+ * sysloginfo is a string identifying the complainant.
+ * queryname is the domain name associated with the problem.
+ * complaint is a string describing what is wrong.
+ * dname and a_rr are the problematic other name server.
+ */
+void
+nslookupComplain(sysloginfo, queryname, complaint, dname, a_rr)
+ char *sysloginfo, *queryname, *complaint, *dname;
+ register struct databuf *a_rr;
+{
+ dprintf(2, (ddt, "NS '%s' %s\n", dname, complaint));
+ if (sysloginfo && queryname && !haveComplained(queryname, complaint))
+ {
+ char buf[512];
+
+ /* syslog only takes 5 params */
+ sprintf(buf, "%s: query(%s) %s (%s:%s)",
+ sysloginfo, queryname,
+ complaint, dname, inet_ntoa(
+ *(struct in_addr*)a_rr->d_data
+ ));
+ syslog(LOG_INFO, buf);
+ }
+}
+
+/*
+ * nslookup(nsp, qp, syslogdname, sysloginfo)
+ * Lookup the address for each nameserver in `nsp' and add it to
+ * the list saved in the qinfo structure pointed to by `qp'.
+ * Omits information about nameservers that we shouldn't ask.
+ * Detects the following dangerous operations:
+ * One of the A records for one of the nameservers in nsp
+ * refers to the address of one of our own interfaces;
+ * One of the A records refers to the nameserver port on
+ * the host that asked us this question.
+ * returns: the number of addresses added, or -1 if a dangerous operation
+ * is detected.
+ * side effects:
+ * if a dangerous situation is detected and (syslogdname && sysloginfo),
+ * calls syslog.
+ */
+int
+nslookup(nsp, qp, syslogdname, sysloginfo)
+ struct databuf *nsp[];
+ register struct qinfo *qp;
+ char *syslogdname;
+ char *sysloginfo;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *nsdp;
+ register struct qserv *qs;
+ register int n;
+ register unsigned int i;
+ struct hashbuf *tmphtp;
+ char *dname, *fname;
+ int oldn, naddr, class, found_arr;
+ time_t curtime;
+
+ dprintf(3, (ddt, "nslookup(nsp=0x%x, qp=0x%x, \"%s\")\n",
+ nsp, qp, syslogdname));
+
+ naddr = n = qp->q_naddr;
+ curtime = (u_long) tt.tv_sec;
+ while ((nsdp = *nsp++) != NULL) {
+ class = nsdp->d_class;
+ dname = (char *)nsdp->d_data;
+ dprintf(3, (ddt, "nslookup: NS \"%s\" c=%d t=%d (0x%x)\n",
+ dname, class, nsdp->d_type, nsdp->d_flags));
+
+ /* don't put in servers we have tried */
+ for (i = 0; i < qp->q_nusedns; i++) {
+ if (qp->q_usedns[i] == nsdp) {
+ dprintf(2, (ddt,
+ "skipping used NS w/name %s\n",
+ nsdp->d_data));
+ goto skipserver;
+ }
+ }
+
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ?fcachetab :hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL || fname != dname) {
+ dprintf(3, (ddt, "%s: not found %s %x\n",
+ dname, fname, np));
+ continue;
+ }
+ found_arr = 0;
+ oldn = n;
+
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ struct in_addr nsa;
+
+ if (dp->d_type == T_CNAME && dp->d_class == class)
+ goto skipserver;
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ /*
+ * 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) )
+ {
+ dprintf(3, (ddt,
+ "nslookup: stale entry '%s'\n",
+ np->n_dname));
+ /* Cache invalidate the NS RR's */
+ if (dp->d_ttl < curtime)
+ delete_all(np, class, T_A);
+ n = oldn;
+ break;
+ }
+#ifdef VALIDATE
+ /* anant@isi.edu validation procedure, maintains a
+ * table of server names-addresses used recently
+ */
+ store_name_addr(dname, (struct in_addr *)dp->d_data,
+ syslogdname, sysloginfo);
+#endif /*VALIDATE*/
+
+ found_arr++;
+ nsa = *(struct in_addr *)dp->d_data;
+ /* don't put in duplicates */
+ qs = qp->q_addr;
+ for (i = 0; i < n; i++, qs++)
+ if (qs->ns_addr.sin_addr.s_addr == nsa.s_addr)
+ goto skipaddr;
+ qs->ns_addr.sin_family = AF_INET;
+ qs->ns_addr.sin_port = ns_port;
+ qs->ns_addr.sin_addr = nsa;
+ qs->ns = nsdp;
+ qs->nsdata = dp;
+ qs->nretry = 0;
+ /*
+ * if we are being asked to fwd a query whose
+ * nameserver list includes our own name/address(es),
+ * then we have detected a lame delegation and rather
+ * than melt down the network and hose down the other
+ * servers (who will hose us in return), we'll return
+ * -1 here which will cause SERVFAIL to be sent to
+ * the client's resolver which will hopefully then
+ * shut up.
+ *
+ * (originally done in nsContainsUs by vix@dec mar92;
+ * moved into nslookup by apb@und jan1993)
+ */
+ if (aIsUs(nsa)) {
+ static char *complaint = "contains our address";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp);
+ return (-1);
+ }
+ /*
+ * If we want to forward to a host that asked us
+ * this question then either we or they are sick
+ * (unless they asked from some port other than
+ * their nameserver port). (apb@und jan1993)
+ */
+ if (bcmp((char *)&qp->q_from, (char *)&qs->ns_addr,
+ sizeof(qp->q_from)) == 0)
+ {
+ static char *complaint = "forwarding loop";
+ nslookupComplain(sysloginfo, syslogdname,
+ complaint, dname, dp);
+ return (-1);
+ }
+ /*
+ * Don't forward queries to bogus servers. Note
+ * that this is unlike the previous tests, which
+ * are fatal to the query. Here we just skip the
+ * server, which is only fatal if it's the last
+ * server. Note also that we antialias here -- all
+ * A RR's of a server are considered the same server,
+ * and if any of them is bogus we skip the whole
+ * server. Those of you using multiple A RR's to
+ * load-balance your servers will (rightfully) lose
+ * here. But (unfortunately) only if they are bogus.
+ */
+ if (addr_on_netlist(nsa, boglist))
+ goto skipserver;
+
+ n++;
+ if (n >= NSMAX)
+ goto out;
+ skipaddr: ;
+ }
+ dprintf(8, (ddt, "nslookup: %d ns addrs\n", n));
+ if (found_arr == 0 && !(qp->q_flags & Q_SYSTEM))
+ (void) sysquery(dname, class, T_A, NULL, 0);
+skipserver: ;
+ }
+out:
+ dprintf(3, (ddt, "nslookup: %d ns addrs total\n", n));
+ qp->q_naddr = n;
+#ifdef DATUMREFCNT
+ /* must be run before the sort */
+ for (i = naddr ; i < n ; i++) {
+ qp->q_addr[i].nsdata->d_rcnt++;
+ qp->q_addr[i].ns->d_rcnt++;
+ }
+#endif
+ if (n > 1) {
+ qsort((char *)qp->q_addr, n, sizeof(struct qserv),
+ (int (*)__P((const void *, const void *)))qcomp);
+ }
+ return (n - naddr);
+}
+
+/*
+ * qcomp - compare two NS addresses, and return a negative, zero, or
+ * positive value depending on whether the first NS address is
+ * "better than", "equally good as", or "inferior to" the second
+ * NS address.
+ *
+ * How "goodness" is defined (for the purposes of this routine):
+ * - If the estimated round trip times differ by an amount deemed significant
+ * then the one with the smaller estimate is preferred; else
+ * - If we can determine which one is topologically closer then the
+ * closer one is preferred; else
+ * - The one with the smaller estimated round trip time is preferred
+ * (zero is returned if the two estimates are identical).
+ *
+ * How "topological closeness" is defined (for the purposes of this routine):
+ * Ideally, named could consult some magic map of the Internet and
+ * determine the length of the path to an arbitrary destination. Sadly,
+ * no such magic map exists. However, named does have a little bit of
+ * topological information in the form of the sortlist (which includes
+ * the directly connected subnet(s), the directly connected net(s), and
+ * any additional nets that the administrator has added using the "sortlist"
+ * directive in the bootfile. Thus, if only one of the addresses matches
+ * something in the sortlist then it is considered to be topologically
+ * closer. If both match, but match different entries in the sortlist,
+ * then the one that matches the entry closer to the beginning of the
+ * sorlist is considered to be topologically closer. In all other cases,
+ * topological closeness is ignored because it's either indeterminate or
+ * equal.
+ *
+ * How times are compared:
+ * Both times are rounded to the closest multiple of the NOISE constant
+ * defined below and then compared. If the rounded values are equal
+ * then the difference in the times is deemed insignificant. Rounding
+ * is used instead of merely taking the absolute value of the difference
+ * because doing the latter would make the ordering defined by this
+ * routine be incomplete in the mathematical sense (e.g. A > B and
+ * B > C would not imply A > C). The mathematics are important in
+ * practice to avoid core dumps in qsort().
+ *
+ * XXX: this doesn't solve the European root nameserver problem very well.
+ * XXX: we should detect and mark as inferior nameservers that give bogus
+ * answers
+ *
+ * (this was originally vixie's stuff but almquist fixed fatal bugs in it
+ * and wrote the above documentation)
+ */
+
+/*
+ * RTT delta deemed to be significant, in milliseconds. With the current
+ * definition of RTTROUND it must be a power of 2.
+ */
+#define NOISE 128 /* milliseconds; 0.128 seconds */
+
+#define sign(x) (((x) < 0) ? -1 : ((x) > 0) ? 1 : 0)
+#define RTTROUND(rtt) (((rtt) + (NOISE >> 1)) & ~(NOISE - 1))
+
+int
+qcomp(qs1, qs2)
+ struct qserv *qs1, *qs2;
+{
+ int pos1, pos2, pdiff;
+ u_long rtt1, rtt2;
+ long tdiff;
+
+ if ((!qs1->nsdata) || (!qs2->nsdata))
+ return 0;
+ rtt1 = qs1->nsdata->d_nstime;
+ rtt2 = qs2->nsdata->d_nstime;
+
+ dprintf(10, (ddt, "qcomp(%s, %s) %lu (%lu) - %lu (%lu) = %lu",
+ inet_ntoa(qs1->ns_addr.sin_addr),
+ inet_ntoa(qs2->ns_addr.sin_addr),
+ rtt1, RTTROUND(rtt1), rtt2, RTTROUND(rtt2),
+ rtt1 - rtt2));
+ if (RTTROUND(rtt1) == RTTROUND(rtt2)) {
+ pos1 = position_on_netlist(qs1->ns_addr.sin_addr, nettab);
+ pos2 = position_on_netlist(qs2->ns_addr.sin_addr, nettab);
+ pdiff = pos1 - pos2;
+ dprintf(10, (ddt, ", pos1=%d, pos2=%d\n", pos1, pos2));
+ if (pdiff)
+ return (pdiff);
+ } else {
+ dprintf(10, (ddt, "\n"));
+ }
+ tdiff = rtt1 - rtt2;
+ return (sign(tdiff));
+}
+#undef sign
+#undef RTTROUND
+
+/*
+ * Arrange that forwarded query (qp) is retried after t seconds.
+ * Query list will be sorted after z_time is updated.
+ */
+void
+schedretry(qp, t)
+ struct qinfo *qp;
+ time_t t;
+{
+ register struct qinfo *qp1, *qp2;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt,"schedretry(0x%x, %ld sec)\n", qp, (long)t);
+ if (qp->q_time)
+ fprintf(ddt,
+ "WARNING: schedretry(%#x, %d) q_time already %d\n",
+ qp, t, 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.
+ */
+void
+unsched(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+
+ dprintf(3, (ddt, "unsched(%#x, %d )\n", qp, ntohs(qp->q_id)));
+ 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'.
+ */
+void
+retry(qp)
+ register struct qinfo *qp;
+{
+ register int n;
+ register HEADER *hp;
+ struct sockaddr_in *nsa;
+
+ dprintf(3, (ddt, "retry(x%x) id=%d\n", qp, ntohs(qp->q_id)));
+
+ if (qp->q_msg == NULL) { /* XXX - why? */
+ qremove(qp);
+ return;
+ }
+
+ if (qp->q_expire && (qp->q_expire < tt.tv_sec)) {
+ dprintf(1, (ddt,
+ "retry(x%x): expired @ %d (%d secs before now (%d))\n",
+ qp, qp->q_expire, tt.tv_sec - qp->q_expire,
+ tt.tv_sec));
+ if (qp->q_stream) /* return failure code on stream */
+ goto fail;
+ qremove(qp);
+ return;
+ }
+
+ /* 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 >= (int)qp->q_naddr)
+ n = 0;
+ if (qp->q_addr[n].nretry < MAXRETRY)
+ goto found;
+ } while (n != qp->q_curaddr);
+ }
+fail:
+ /*
+ * Give up. Can't reach destination.
+ */
+ hp = (HEADER *)(qp->q_cmsg ? qp->q_cmsg : qp->q_msg);
+ if (qp->q_flags & Q_PRIMING) {
+ /* 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 < (int)qp->q_naddr; n++)
+ qp->q_addr[n].nretry = 0;
+ return;
+ }
+ dprintf(5, (ddt, "give up\n"));
+ 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((u_char *)hp, n, qp)) {
+ dprintf(1, (ddt,"gave up retry(x%x) nsid=%d id=%d\n",
+ qp, ntohs(qp->q_nsid), ntohs(qp->q_id)));
+ }
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ 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);
+ nsa = Q_NEXTADDR(qp, n);
+ dprintf(1, (ddt,
+ "%s(addr=%d n=%d) -> [%s].%d ds=%d nsid=%d id=%d %dms\n",
+ (qp->q_fwd ? "reforw" : "resend"),
+ n, qp->q_addr[n].nretry,
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[n].nsdata != 0)
+ ? qp->q_addr[n].nsdata->d_nstime
+ : (-1)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ /* NOSTRICT */
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ dprintf(3, (ddt, "error resending msg errno=%d\n", errno));
+ }
+ hp->rd = 1; /* leave set to 1 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentDupQ);
+ unsched(qp);
+#ifdef SLAVE_FORWARD
+ if(forward_only)
+ schedretry(qp, (time_t)slave_retry);
+ else
+#endif /* SLAVE_FORWARD */
+ 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)
+ struct qinfo *qp;
+{
+ time_t t, u, v;
+ struct qserv *ns = &qp->q_addr[qp->q_curaddr];
+
+ if (ns->nsdata != NULL)
+ t = (time_t) MAX(RETRYBASE, 2 * ns->nsdata->d_nstime / 1000);
+ else
+ t = (time_t) RETRYBASE;
+ u = t << ns->nretry;
+ v = MIN(u, RETRY_TIMEOUT); /* max. retry timeout for now */
+ dprintf(3, (ddt, "retrytime: nstime%ldms t%ld nretry%ld u%ld : v%ld\n",
+ ns->nsdata ?(long)(ns->nsdata->d_nstime / 1000) :(long)-1,
+ (long)t, (long)ns->nretry, (long)u, (long)v));
+ return (v);
+}
+
+void
+qflush()
+{
+ while (qhead)
+ qremove(qhead);
+ qhead = QINFO_NULL;
+}
+
+void
+qremove(qp)
+ register struct qinfo *qp;
+{
+ dprintf(3, (ddt, "qremove(x%x)\n", qp));
+
+ if (qp->q_flags & Q_ZSERIAL)
+ qserial_answer(qp, 0);
+ unsched(qp);
+ qfree(qp);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+struct qinfo *
+qfindid(u_int16_t id)
+#else
+struct qinfo *
+qfindid(id)
+ register u_int16_t id;
+#endif
+{
+ register struct qinfo *qp;
+
+ dprintf(3, (ddt, "qfindid(%d)\n", ntohs(id)));
+ for (qp = qhead; qp!=QINFO_NULL; qp = qp->q_link) {
+ if (qp->q_nsid == id)
+ return(qp);
+ }
+ dprintf(5, (ddt, "qp not found\n"));
+ return (NULL);
+}
+
+struct qinfo *
+#ifdef DMALLOC
+qnew_tagged(file, line)
+ char *file;
+ int line;
+#else
+qnew()
+#endif
+{
+ register struct qinfo *qp;
+
+ if ((qp = (struct qinfo *)
+#ifdef DMALLOC
+ dcalloc(file, line,
+#else
+ calloc(
+#endif
+ 1, sizeof(struct qinfo))) == NULL) {
+ dprintf(5, (ddt, "qnew: calloc error\n"));
+ syslog(LOG_ERR, "forw: %m");
+ exit(12);
+ }
+ dprintf(5, (ddt, "qnew(x%x)\n", qp));
+ qp->q_link = qhead;
+ qhead = qp;
+ return (qp);
+}
+
+void
+qfree(qp)
+ struct qinfo *qp;
+{
+ register struct qinfo *np;
+ register struct databuf *dp;
+#ifdef DATUMREFCNT
+ int i;
+#endif
+
+#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);
+#ifdef DATUMREFCNT
+ for (i = 0 ; i < (int)qp->q_naddr ; i++) {
+ dp = qp->q_addr[i].ns;
+ if (dp)
+ if (--(dp->d_rcnt)) {
+ dprintf(3, (ddt, "qfree: ns %s rcnt %d\n",
+ dp->d_data,
+ dp->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "qfree: ns %s rcnt %d delayed\n",
+ dp->d_data,
+ dp->d_rcnt));
+ free((char*)dp);
+ }
+ dp = qp->q_addr[i].nsdata;
+ if (dp)
+ if ((--(dp->d_rcnt))) {
+ dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d\n",
+ *(int32_t *)(dp->d_data),
+ dp->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "qfree: nsdata %08.8X rcnt %d delayed\n",
+ *(int32_t *)(dp->d_data),
+ dp->d_rcnt));
+ free((char*)dp);
+ }
+ }
+#endif
+ 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;
+ }
+ }
+ free((char *)qp);
+}
diff --git a/usr.sbin/named/ns_func.h b/usr.sbin/named/ns_func.h
new file mode 100644
index 0000000..eaff3bf
--- /dev/null
+++ b/usr.sbin/named/ns_func.h
@@ -0,0 +1,140 @@
+/* ns_func.h - declarations for ns_*.c's externally visible functions
+ *
+ * $Id: ns_func.h,v 1.12 1994/07/22 08:42:39 vixie Exp $
+ */
+
+/* ++from ns_resp.c++ */
+extern void ns_resp __P((u_char *, int)),
+ prime_cache __P((void)),
+ delete_all __P((struct namebuf *, int, int));
+extern struct qinfo *sysquery __P((char *, int, int,
+ struct in_addr *, int));
+extern int
+ doupdate __P((u_char *, int, u_char *, int,
+ struct databuf **, int, u_int)),
+ send_msg __P((u_char *, int, struct qinfo *)),
+ findns __P((struct namebuf **, int,
+ struct databuf **, int *, int)),
+ finddata __P((struct namebuf *, int, int, HEADER *,
+ char **, int *, int *)),
+ wanted __P((struct databuf *, int, int)),
+ add_data __P((struct namebuf *,
+ struct databuf **,
+ u_char *, int));
+/* --from ns_resp.c-- */
+
+/* ++from ns_req.c++ */
+extern void ns_req __P((u_char *, int, int,
+ struct qstream *,
+ struct sockaddr_in *,
+ int));
+extern int stale __P((struct databuf *)),
+ make_rr __P((char *, struct databuf *,
+ u_char *, int, int)),
+ doaddinfo __P((HEADER *, u_char *, int)),
+ doaddauth __P((HEADER *, u_char *, int,
+ struct namebuf *,
+ struct databuf *));
+/* --from ns_req.c-- */
+
+/* ++from ns_forw.c++ */
+extern time_t retrytime __P((struct qinfo *));
+extern int ns_forw __P((struct databuf *nsp[],
+ u_char *msg,
+ int msglen,
+ struct sockaddr_in *fp,
+ struct qstream *qsp,
+ int dfd,
+ struct qinfo **qpp,
+ char *dname,
+ struct namebuf *np)),
+ haveComplained __P((char *, char *)),
+ nslookup __P((struct databuf *nsp[],
+ struct qinfo *qp,
+ char *syslogdname,
+ char *sysloginfo)),
+ qcomp __P((struct qserv *, struct qserv *));
+extern struct qdatagram *aIsUs __P((struct in_addr));
+extern void nslookupComplain __P((char *, char *, char *, char *,
+ struct databuf *)),
+ schedretry __P((struct qinfo *, time_t)),
+ unsched __P((struct qinfo *)),
+ retry __P((struct qinfo *)),
+ qflush __P((void)),
+ qremove __P((struct qinfo *)),
+ qfree __P((struct qinfo *));
+extern struct qinfo *qfindid __P((u_int16_t)),
+#ifdef DMALLOC
+ *qnew_tagged __P((void));
+# define qnew() qnew_tagged(__FILE__, __LINE__)
+#else
+ *qnew();
+#endif
+/* --from ns_forw.c-- */
+
+/* ++from ns_main.c++ */
+extern u_int32_t net_mask __P((struct in_addr));
+extern void sqrm __P((struct qstream *)),
+ sqflush __P((struct qstream *allbut)),
+ dqflush __P((time_t gen)),
+ sq_done __P((struct qstream *)),
+ ns_setproctitle __P((char *, int)),
+ getnetconf __P((void));
+extern struct netinfo *findnetinfo __P((struct in_addr));
+/* --from ns_main.c-- */
+
+/* ++from ns_maint.c++ */
+extern void ns_maint __P((void)),
+ sched_maint __P((void)),
+#ifdef CLEANCACHE
+ remove_zone __P((struct hashbuf *, int, int)),
+#else
+ remove_zone __P((struct hashbuf *, int)),
+#endif
+ loadxfer __P((void)),
+ qserial_answer __P((struct qinfo *, u_int32_t));
+extern SIG_FN endxfer __P((void));
+#ifdef DEBUG
+extern void printzoneinfo __P((int));
+#endif
+/* --from ns_maint.c-- */
+
+/* ++from ns_sort.c++ */
+extern struct netinfo *local __P((struct sockaddr_in *));
+extern void sort_response __P((u_char *, int,
+ struct netinfo *,
+ u_char *));
+/* --from ns_sort.c-- */
+
+/* ++from ns_init.c++ */
+extern void ns_init __P((char *));
+/* --from ns_init.c-- */
+
+/* ++from ns_ncache.c++ */
+extern void cache_n_resp __P((u_char *, int));
+/* --from ns_ncache.c-- */
+
+/* ++from ns_stats.c++ */
+extern void ns_stats __P((void));
+extern void qtypeIncr __P((int qtype));
+extern struct nameser *nameserFind __P((struct in_addr addr, int flags));
+#define NS_F_INSERT 0x0001
+extern void nameserIncr __P((struct in_addr addr,
+ enum nameserStats which));
+/* --from ns_stats.c-- */
+
+/* ++from ns_validate.c++ */
+extern int
+#ifdef NCACHE
+ validate __P((char *, struct sockaddr_in *,
+ int, int, char *, int, int)),
+#else
+ validate __P((char *, struct sockaddr_in *,
+ int, int, char *, int)),
+#endif
+ dovalidate __P((u_char *, int, u_char *, int, int,
+ struct sockaddr_in *, int *)),
+ update_msg __P((u_char *, int *, int Vlist[], int));
+extern void store_name_addr __P((char *, struct in_addr *,
+ char *, char *));
+/* --from ns_validate.c-- */
diff --git a/usr.sbin/named/ns_glob.h b/usr.sbin/named/ns_glob.h
new file mode 100644
index 0000000..993d14d
--- /dev/null
+++ b/usr.sbin/named/ns_glob.h
@@ -0,0 +1,245 @@
+/*
+ * from ns.h 4.33 (Berkeley) 8/23/90
+ * $Id: ns_glob.h,v 1.7 1994/06/11 22:04:46 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/*
+ * Global variables for the name server.
+ */
+
+#ifdef DEBUG
+DECL int debug INIT(0);
+DECL FILE *ddt INIT(NULL);
+#endif
+
+ /* list of open streams */
+DECL struct qstream *streamq INIT(QSTREAM_NULL);
+
+ /* list of datagram interfaces */
+DECL struct qdatagram *datagramq INIT(QDATAGRAM_NULL);
+
+ /* often set to the current time */
+DECL struct timeval tt;
+
+ /* head of allocated queries */
+DECL struct qinfo *qhead INIT(QINFO_NULL);
+
+ /* list of forwarding hosts */
+DECL struct fwdinfo *fwdtab INIT(NULL);
+
+ /* next forwarded query id */
+DECL int nsid INIT(0);
+
+ /* datagram socket */
+DECL int ds INIT(-1);
+
+ /* listening TCP socket */
+DECL int vs INIT(-1);
+
+ /* received SIGHUP, need to reload db */
+DECL int needreload INIT(0);
+
+ /* need to call ns_maint()*/
+DECL int needmaint INIT(0);
+
+ /* how often does ns_maint() need to be called, in seconds? */
+ /* (beware: this is also the upper bound on named_xfer real time) */
+DECL int maint_interval INIT(15*60);
+
+ /* need to reload secondary zone(s) */
+DECL int needzoneload INIT(0);
+
+ /* need to dump database */
+DECL int needToDoadump INIT(0);
+
+ /* need to checkpoint cache */
+DECL int needToChkpt INIT(0);
+
+ /* need to dump statistics */
+DECL int needStatsDump INIT(0);
+
+#ifdef ALLOW_UPDATES
+ /* 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)
+ */
+DECL int needToExit INIT(0);
+#endif /* ALLOW_UPDATES */
+
+#ifdef QRYLOG
+ /* is query logging turned on? */
+DECL int qrylog INIT(0);
+#endif /*QRYLOG*/
+
+ /* is this a root server that should therefore not recurse? */
+DECL int NoRecurse INIT(0);
+
+/*
+ * 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.
+ */
+DECL struct netinfo *nettab INIT(NULL);
+DECL struct netinfo **elocal INIT(&nettab);
+DECL struct netinfo **enettab INIT(&nettab);
+
+#ifdef XFRNETS
+ /* list of nets we're willing to zone transfer to */
+DECL struct netinfo *xfrnets INIT(NULL);
+#endif
+
+#ifdef BOGUSNS
+ /* list of bogus nameservers */
+DECL struct netinfo *boglist INIT(NULL);
+#endif
+
+ /* loopback net */
+DECL struct netinfo netloop;
+
+ /* port to which we send queries */
+DECL u_int16_t ns_port;
+
+ /* Source addr of last packet */
+DECL struct sockaddr_in from_addr;
+
+ /* Source addr size of last packet */
+DECL int from_len;
+
+ /* Used by ns_stats */
+DECL time_t boottime,
+ resettime;
+
+ /* next query to retry */
+DECL struct qinfo *retryqp INIT(NULL);
+
+ /* default boot file */
+#ifdef BOOTFILE
+DECL char *bootfile INIT(BOOTFILE);
+#else
+DECL char *bootfile INIT(_PATH_BOOT);
+#endif
+
+ /* default debug output file */
+#ifdef DEBUGFILE
+DECL char *debugfile INIT(DEBUGFILE);
+#else
+DECL char *debugfile INIT(_PATH_DEBUG);
+#endif
+
+#ifdef WANT_PIDFILE
+ /* file to store current named PID */
+#ifdef PIDFILE
+DECL char *PidFile INIT(PIDFILE);
+#else
+DECL char *PidFile INIT(_PATH_PIDFILE);
+#endif
+#endif /*WANT_PIDFILE*/
+
+ /* zone information */
+DECL struct zoneinfo *zones INIT(NULL);
+
+ /* number of zones in use */
+DECL int nzones INIT(0);
+
+ /* true on slave server */
+DECL int forward_only INIT(0);
+
+ /* set if we need a priming */
+DECL int needs_prime_cache INIT(0);
+
+ /* is cache being primed */
+DECL int priming INIT(0);
+
+ /* ptrs to dnames in msg for dn_comp */
+DECL u_char *dnptrs[40];
+
+ /* number of names in addinfo */
+DECL int addcount;
+
+ /* name of cache file */
+DECL char *cache_file;
+
+#ifdef LOCALDOM
+ /* our local domain (deprecated in favor of resolv.conf) */
+DECL char *localdomain;
+#endif
+
+#ifdef SLAVE_FORWARD
+ /* retry time when a slave */
+DECL int slave_retry INIT(4);
+#endif
+
+#ifdef STATSFILE
+DECL char *statsfile INIT(STATSFILE);
+#else
+DECL char *statsfile INIT(_PATH_STATS);
+#endif
+
+DECL char sendtoStr[] INIT("sendto");
+
+ /* defined in version.c, can't use DECL/INIT */
+extern char Version[];
+
+ /* max value of xfers_running */
+DECL int max_xfers_running INIT(MAX_XFERS_RUNNING);
diff --git a/usr.sbin/named/ns_init.c b/usr.sbin/named/ns_init.c
new file mode 100644
index 0000000..82c2071
--- /dev/null
+++ b/usr.sbin/named/ns_init.c
@@ -0,0 +1,808 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_init.c 4.38 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id:";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <signal.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "named.h"
+
+#undef nsaddr
+
+static void zoneinit __P((struct zoneinfo *)),
+ get_forwarders __P((FILE *)),
+ boot_read __P((char *)),
+#ifdef DEBUG
+ content_zone __P((int)),
+#endif
+ free_forwarders __P((void));
+
+static struct zoneinfo *find_zone __P((char *, int, int));
+
+/*
+ * Read boot file for configuration info.
+ */
+void
+ns_init(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ static int loads = 0; /* number of times loaded */
+
+ dprintf(1, (ddt, "\nns_init(%s)\n", bootfile));
+ gettime(&tt);
+
+ 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_flags &= ~Z_FOUND;
+#ifdef LOCALDOM
+ if (localdomain) {
+ free(localdomain);
+ localdomain = NULL;
+ }
+#endif
+ free_forwarders();
+ free_netlist(enettab);
+#ifdef XFRNETS
+ free_netlist(&xfrnets);
+#endif
+#ifdef BOGUSNS
+ free_netlist(&boglist);
+#endif
+ forward_only = 0;
+ }
+
+ dprintf(3, (ddt, "\n content of zones before loading \n"));
+#ifdef DEBUG
+ if (debug >= 3) {
+ content_zone(nzones - 1);
+ }
+#endif
+ boot_read(bootfile);
+
+ /* erase all old zones that were not found */
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type && (zp->z_flags & Z_FOUND) == 0) {
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+#ifdef SECURE_ZONES
+ free_netlist(&zp->secure_nets);
+#endif
+ syslog(LOG_NOTICE, "Zone \"%s\" was removed", zp->z_origin);
+ free(zp->z_origin);
+ free(zp->z_source);
+ bzero((char *) zp, sizeof(*zp));
+ }
+ }
+ dprintf(2, (ddt,"\n content of zones after loading\n"));
+
+#ifdef DEBUG
+ if (debug >= 2) {
+ content_zone(nzones-1);
+ }
+#endif
+
+ /*
+ * Schedule calls to ns_maint().
+ */
+ if (!needmaint)
+ sched_maint();
+ dprintf(1, (ddt, "exit ns_init()%s\n",
+ needmaint ? ", need maintenance immediately" : ""));
+ loads++;
+}
+
+/*
+ * Read the actual boot file.
+ * Set up to recurse.
+ */
+static void
+boot_read(bootfile)
+ char *bootfile;
+{
+ register struct zoneinfo *zp;
+ char buf[BUFSIZ], obuf[BUFSIZ], *source;
+ FILE *fp;
+ int type;
+ int class;
+#ifdef GEN_AXFR
+ char *class_p;
+#endif
+ struct stat f_time;
+ static int tmpnum = 0; /* unique number for tmp zone files */
+#ifdef ALLOW_UPDATES
+ char *cp, *flag;
+#endif
+ int slineno; /* Saved global line number. */
+ int i;
+
+ if ((fp = fopen(bootfile, "r")) == NULL) {
+ syslog(LOG_ERR, "%s: %m", bootfile);
+ exit(1);
+ }
+
+ slineno = lineno;
+ lineno = 0;
+
+ 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_netlist(fp, enettab, ALLOW_NETS, buf);
+ continue;
+ } else if (strcasecmp(buf, "max-fetch") == 0) {
+ max_xfers_running = getnum(fp, bootfile, 0);
+ continue;
+ } else if (strcasecmp(buf, "forwarders") == 0) {
+ get_forwarders(fp);
+ continue;
+ } else if (strcasecmp(buf, "slave") == 0) {
+ forward_only++;
+ endline(fp);
+ continue;
+#ifdef BOGUSNS
+ } else if (strcasecmp(buf, "bogusns") == 0) {
+ get_netlist(fp, &boglist, ALLOW_HOSTS, buf);
+ continue;
+#endif
+#ifdef XFRNETS
+ } else if ((strcasecmp(buf, "tcplist") == 0) ||
+ (strcasecmp(buf, "xfrnets") == 0)) {
+ get_netlist(fp, &xfrnets, ALLOW_NETS, buf);
+ continue;
+#endif
+#ifdef LOCALDOM
+ } else if (strcasecmp(buf, "domain") == 0) {
+ if (getword(buf, sizeof(buf), fp))
+ localdomain = savestr(buf);
+ endline(fp);
+ continue;
+#endif
+ } else if (strcasecmp(buf, "include") == 0) {
+ if (getword(buf, sizeof(buf), fp))
+ boot_read(buf);
+ endline(fp);
+ continue;
+ } else if (strncasecmp(buf, "cache", 5) == 0) {
+ type = Z_CACHE;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+ } else if (strncasecmp(buf, "primary", 7) == 0) {
+ type = Z_PRIMARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+ } else if (strncasecmp(buf, "secondary", 9) == 0) {
+ type = Z_SECONDARY;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#ifdef STUBS
+ } else if (strncasecmp(buf, "stub", 4) == 0) {
+ type = Z_STUB;
+ class = C_IN;
+#ifdef GEN_AXFR
+ if (class_p = strchr(buf, '/'))
+ class = get_class(class_p+1);
+#endif
+#endif
+ } else {
+ syslog(LOG_ERR, "%s: line %d: unknown field '%s'\n",
+ bootfile, lineno+1, 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;
+ }
+ i = strlen(obuf);
+ if ((obuf[i-1] == '.') && (i != 1))
+ syslog(LOG_ERR, "%s: line %d: zone \"%s\" has trailing dot\n",
+ bootfile, lineno, obuf);
+ while ((--i >= 0) && (obuf[i] == '.'))
+ obuf[i] = '\0';
+ dprintf(1, (ddt, "zone origin %s", obuf[0]?obuf:"."));
+ /*
+ * read source file or host address
+ */
+ if (!getword(buf, sizeof(buf), fp)) {
+ syslog(LOG_ERR, "%s: line %d: missing %s\n",
+ bootfile, lineno,
+#ifdef STUBS
+ (type == Z_SECONDARY || type == Z_STUB)
+#else
+ (type == Z_SECONDARY)
+#endif
+ ?"host address"
+ :"source file");
+ continue;
+ }
+
+ /* check for previous instance of this zone (reload) */
+ if (!(zp = find_zone(obuf, type, class))) {
+ if (type == Z_CACHE) {
+ zp = &zones[0];
+ zp->z_origin = "";
+ goto gotcache;
+ }
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++)
+ if (zp->z_type == Z_NIL)
+ goto gotzone;
+ /*
+ * this code assumes that nzones never decreases
+ */
+ if (nzones % 64 == 0) {
+ dprintf(1, (ddt,
+ "Reallocating zones structure\n"));
+ /*
+ * Realloc() not used since it might damage zones
+ * if an error occurs
+ */
+ zp = (struct zoneinfo *)
+ malloc((64 + nzones)
+ * sizeof(struct zoneinfo));
+ if (zp == (struct zoneinfo *)0) {
+ syslog(LOG_ERR,
+ "no memory for more zones");
+ dprintf(1, (ddt,
+ "Out of memory for new zones\n"
+ )
+ );
+ 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);
+ gotcache:
+ zp->z_type = type;
+ zp->z_class = class;
+ }
+ zp->z_addrcnt = 0;
+
+ switch (type) {
+ case Z_CACHE:
+ source = savestr(buf);
+ dprintf(1, (ddt, ", source = %s\n", source));
+ 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) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "cache is up to date\n"));
+ if (source != cache_file)
+ free(source);
+ break; /* zone is already up to date */
+ }
+
+ /* file has changed, or hasn't been loaded yet */
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(fcachetab, 0, 1);
+#else
+ remove_zone(fcachetab, 0);
+#endif
+ }
+ zp->z_source = source;
+ dprintf(1, (ddt, "reloading zone\n"));
+ (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 = strchr(flag, ',');
+ if (cp)
+ *cp++ = 0;
+ if (strcasecmp(flag, "dynamic") == 0)
+ zp->z_flags |= Z_DYNAMIC;
+ else if (strcasecmp(flag, "addonly") == 0)
+ zp->z_flags |= Z_DYNADDONLY;
+ else {
+ syslog(LOG_ERR,
+ "%s: line %d: bad flag '%s'\n",
+ bootfile, lineno, flag);
+ }
+ flag = cp;
+ }
+ }
+#else /*ALLOW_UPDATES*/
+ endline(fp);
+#endif
+
+ dprintf(1, (ddt, ", source = %s\n", source));
+ /*
+ * 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) &&
+ !(zp->z_flags & Z_INCLUDE) &&
+ stat(zp->z_source, &f_time) != -1 &&
+ zp->z_ftime == f_time.st_mtime) {
+ dprintf(1, (ddt, "zone is up to date\n"));
+ free(source);
+ break; /* zone is already up to date */
+ }
+ if (zp->z_source) {
+ free(zp->z_source);
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ zp->z_source = source;
+ zp->z_flags &= ~Z_AUTH;
+ dprintf(1, (ddt, "reloading zone\n"));
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_flags |= Z_AUTH;
+#ifdef ALLOW_UPDATES
+ /* Guarantee calls to ns_maint() */
+ zp->z_refresh = maint_interval;
+#else
+ zp->z_refresh = 0; /* no maintenance needed */
+ zp->z_time = 0;
+#endif
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ source = NULL;
+ dprintf(1, (ddt, "\n\taddrs: "));
+ do {
+ if (!inet_aton(buf,
+ &zp->z_addr[zp->z_addrcnt])
+ ) {
+ source = savestr(buf);
+ endline(fp);
+ break;
+ }
+ dprintf(1, (ddt, "%s, ", buf));
+ if ((int)++zp->z_addrcnt > NSMAX - 1) {
+ zp->z_addrcnt = NSMAX - 1;
+ dprintf(1, (ddt,
+ "\nns.h NSMAX reached\n"));
+ }
+ } while (getword(buf, sizeof(buf), fp));
+ dprintf(1, (ddt, "addrcnt = %d\n", zp->z_addrcnt));
+ if (!source) {
+ /*
+ * We will always transfer this zone again
+ * after a reload.
+ */
+ sprintf(buf, "/%s/NsTmp%d.%d", _PATH_TMPDIR,
+ getpid(), tmpnum++);
+ source = savestr(buf);
+ zp->z_flags |= Z_TMP_FILE;
+ } else
+ zp->z_flags &= ~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) ||
+ (stat(zp->z_source, &f_time) == -1 ||
+ (zp->z_ftime != f_time.st_mtime)))) {
+ dprintf(1, (ddt, "backup file changed\n"));
+ free(zp->z_source);
+ zp->z_source = NULL;
+ zp->z_flags &= ~Z_AUTH;
+ zp->z_serial = 0; /* force xfer */
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ }
+ if (zp->z_source)
+ free(source);
+ else
+ zp->z_source = source;
+ if (!(zp->z_flags & Z_AUTH))
+ zoneinit(zp);
+#ifdef FORCED_RELOAD
+ else {
+ /*
+ ** Force secondary to try transfer right away
+ ** after SIGHUP.
+ */
+ if (reloading) {
+ zp->z_time = tt.tv_sec;
+ needmaint = 1;
+ }
+ }
+#endif /* FORCED_RELOAD */
+ break;
+
+ }
+ zp->z_flags |= Z_FOUND;
+ dprintf(1, (ddt, "zone[%d] type %d: '%s'",
+ zp-zones, type,
+ *(zp->z_origin) == '\0' ? "." : zp->z_origin));
+ 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;
+ dprintf(1, (ddt, " z_time %d, z_refresh %d\n",
+ zp->z_time, zp->z_refresh));
+ }
+ (void) my_fclose(fp);
+ lineno = slineno;
+}
+
+static void
+zoneinit(zp)
+ register struct zoneinfo *zp;
+{
+ 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)
+ 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_flags |= Z_AUTH;
+ }
+}
+
+#ifdef ALLOW_UPDATES
+/*
+ * Look for the authoritative zone with the longest matching RHS of dname
+ * and return its zone # or zero if not found.
+ */
+int
+findzone(dname, class)
+ char *dname;
+ int class;
+{
+ char *dZoneName, *zoneName;
+ int dZoneNameLen, zoneNameLen;
+ int maxMatchLen = 0;
+ int maxMatchZoneNum = 0;
+ int zoneNum;
+
+ dprintf(4, (ddt, "findzone(dname=%s, class=%d)\n", dname, class));
+#ifdef DEBUG
+ if (debug >= 5) {
+ fprintf(ddt, "zone dump:\n");
+ for (zoneNum = 1; zoneNum < nzones; zoneNum++)
+ printzoneinfo(zoneNum);
+ }
+#endif
+
+ dZoneName = strchr(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;
+ dprintf(5, (ddt, "about to strncasecmp('%s', '%s', %d)\n",
+ dZoneName, zoneName, dZoneNameLen));
+ if (strncasecmp(dZoneName, zoneName, dZoneNameLen) == 0) {
+ dprintf(5, (ddt, "match\n"));
+ /*
+ * 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;
+ }
+ } else {
+ dprintf(5, (ddt, "no match\n"));
+ }
+ }
+ dprintf(4, (ddt, "findzone: returning %d\n", maxMatchZoneNum));
+ return (maxMatchZoneNum);
+}
+#endif /* ALLOW_UPDATES */
+
+static void
+get_forwarders(fp)
+ FILE *fp;
+{
+ char buf[BUFSIZ];
+ register struct fwdinfo *fip = NULL, *ftp = NULL;
+
+#ifdef SLAVE_FORWARD
+ int forward_count = 0;
+#endif
+
+ dprintf(1, (ddt, "forwarders "));
+
+ /* on mulitple forwarder lines, move to end of the list */
+#ifdef SLAVE_FORWARD
+ if (fwdtab != NULL){
+ forward_count++;
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next)
+ forward_count++;
+ }
+#else
+ if (fwdtab != NULL) {
+ for (fip = fwdtab; fip->next != NULL; fip = fip->next) {
+ ;
+ }
+ }
+#endif /* SLAVE_FORWARD */
+
+ while (getword(buf, sizeof(buf), fp)) {
+ if (strlen(buf) == 0)
+ break;
+ dprintf(1, (ddt," %s",buf));
+ if (ftp == NULL)
+ ftp = (struct fwdinfo *)malloc(sizeof(struct fwdinfo));
+ if (inet_aton(buf, &ftp->fwdaddr.sin_addr)) {
+ ftp->fwdaddr.sin_port = ns_port;
+ ftp->fwdaddr.sin_family = AF_INET;
+ } else {
+ syslog(LOG_ERR, "'%s' (ignored, NOT dotted quad)",
+ buf);
+ dprintf(1, (ddt, " (ignored, NOT dotted quad)"));
+ continue;
+ }
+#ifdef FWD_LOOP
+ if (aIsUs(ftp->fwdaddr.sin_addr)) {
+ syslog(LOG_ERR,
+ "Forwarder '%s' ignored, my address",
+ buf);
+ dprintf(1, (ddt, " (ignored, my address)"));
+ continue;
+ }
+#endif /* FWD_LOOP */
+ ftp->next = NULL;
+ if (fwdtab == NULL)
+ fwdtab = ftp; /* First time only */
+ else
+ fip->next = ftp;
+ fip = ftp;
+ ftp = NULL;
+#ifdef SLAVE_FORWARD
+ forward_count++;
+#endif /* SLAVE_FORWARD */
+ }
+ if (ftp)
+ free((char *)ftp);
+
+#ifdef SLAVE_FORWARD
+ /*
+ ** Set the slave retry time to 60 seconds total divided
+ ** between each forwarder
+ */
+ if (forward_count != 0) {
+ slave_retry = (int) (60 / forward_count);
+ if(slave_retry <= 0)
+ slave_retry = 1;
+ }
+#endif
+
+ dprintf(1, (ddt, "\n"));
+#ifdef DEBUG
+ 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
+}
+
+static void
+free_forwarders()
+{
+ register struct fwdinfo *ftp, *fnext;
+
+ for (ftp = fwdtab; ftp != NULL; ftp = fnext) {
+ fnext = ftp->next;
+ free((char *)ftp);
+ }
+ fwdtab = NULL;
+}
+
+static struct zoneinfo *
+find_zone(name, type, class)
+ char *name;
+ int type, class;
+{
+ register struct zoneinfo *zp;
+
+ for (zp = &zones[1]; zp < &zones[nzones]; zp++) {
+ if (zp->z_type == type && zp->z_class == class &&
+ strcasecmp(name, zp->z_origin) == 0) {
+ dprintf(2, (ddt, ", old zone (%d)", zp - zones));
+ return (zp);
+ }
+ }
+ dprintf(2, (ddt, ", new zone"));
+ return NULL;
+}
+
+#ifdef DEBUG
+/* prints out the content of zones */
+static void
+content_zone(end)
+ int end;
+{
+ int i;
+
+ for (i = 1; i <= end; i++) {
+ printzoneinfo(i);
+ }
+}
+#endif
diff --git a/usr.sbin/named/ns_main.c b/usr.sbin/named/ns_main.c
new file mode 100644
index 0000000..8b04a49
--- /dev/null
+++ b/usr.sbin/named/ns_main.c
@@ -0,0 +1,1581 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_main.c 4.55 (Berkeley) 7/1/91";
+static char rcsid[] = "$Id: ns_main.c,v 4.9.1.19 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1989, 1990
+ * -
+ * Copyright (c) 1986, 1989, 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.
+ * -
+ * 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--
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1986, 1989, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ portions Copyright (c) 1993 Berkeley Network Software Consortium\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Internet Name server (see rfc883 & others).
+ */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#if !defined(SYSV) && defined(XXX)
+#include <sys/wait.h>
+#endif /* !SYSV */
+#include <sys/time.h>
+#define TIME_H_INCLUDED
+#include <sys/resource.h>
+#if defined(__osf__)
+#define _SOCKADDR_LEN /* XXX - should be in portability.h but that
+ * would need to be included before socket.h
+ */
+#endif
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+#include <signal.h>
+#include <netdb.h>
+#include <resolv.h>
+#if defined(SVR4)
+# include <sys/sockio.h>
+#endif
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+#undef nsaddr
+
+ /* UDP receive, TCP send buffer size */
+static const int rbufsize = 8 * 1024;
+
+static struct sockaddr_in nsaddr;
+static u_int16_t local_ns_port; /* our service port */
+static fd_set mask; /* open descriptors */
+static char **Argv = NULL;
+static char *LastArg = NULL; /* end of argv */
+
+static struct qstream *sqadd __P((void));
+static void sq_query __P((struct qstream *)),
+ opensocket __P((struct qdatagram *)),
+#ifdef DEBUG
+ printnetinfo __P((struct netinfo *)),
+#endif
+ setdebug __P((int));
+static int sq_here __P((struct qstream *));
+
+static SIG_FN onintr __P(()),
+ maint_alarm __P(()),
+ setdumpflg __P(()),
+ onhup __P(()),
+#if defined(QRYLOG) && defined(SIGWINCH)
+ setQrylogFlg __P(()),
+#endif
+ setIncrDbgFlg __P(()),
+ setNoDbgFlg __P(()),
+#ifdef SIGSYS
+ sigprof __P(()),
+#endif /* SIGSYS */
+ setchkptflg __P(()),
+ setstatsflg __P(());
+
+static void
+usage()
+{
+ fprintf(stderr,
+"Usage: named [-d #] [-q] [-r] [-p port[/localport]] [[-b] bootfile]\n");
+ exit(1);
+}
+
+/*ARGSUSED*/
+void
+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 nfds;
+ const int on = 1;
+ int len;
+ int rfd, size;
+ time_t lasttime, maxctime;
+ u_char buf[BUFSIZ];
+#ifndef SYSV
+ struct sigvec vec;
+#endif
+ fd_set tmpmask;
+ struct timeval t, *tp;
+ struct qstream *candidate = QSTREAM_NULL;
+ char **argp;
+#ifdef PID_FIX
+ char oldpid[10];
+#endif
+#ifdef WANT_PIDFILE
+ FILE *fp; /* file descriptor for pid file */
+#endif
+#ifdef IP_OPTIONS
+ u_char ip_opts[50]; /* arbitrary size */
+#endif
+
+ local_ns_port = ns_port = htons(NAMESERVER_PORT);
+
+ /*
+ ** Save start and extent of argv for ns_setproctitle().
+ */
+
+ Argv = argp = argv;
+ while (*argp)
+ argp++;
+ LastArg = argp[-1] + strlen(argp[-1]);
+
+ (void) umask(022);
+ /* XXX - should use getopt here */
+ while (--argc > 0) {
+ arg = *++argv;
+ if (*arg == '-') {
+ while (*++arg)
+ switch (*arg) {
+ case 'b':
+ if (--argc <= 0)
+ usage();
+ bootfile = savestr(*++argv);
+ break;
+
+ case 'd':
+ ++argv;
+
+ if (*argv != 0) {
+ if (**argv == '-') {
+ argv--;
+ break;
+ }
+#ifdef DEBUG
+ debug = atoi(*argv);
+#endif
+ --argc;
+ }
+#ifdef DEBUG
+ if (debug <= 0)
+ debug = 1;
+ setdebug(1);
+#endif
+ break;
+
+ case 'p':
+ /* use nonstandard port number.
+ * usage: -p remote/local
+ * remote is the port number to which
+ * we send queries. local is the port
+ * on which we listen for queries.
+ * local defaults to same as remote.
+ */
+ if (--argc <= 0)
+ usage();
+ ns_port = htons((u_int16_t)
+ atoi(*++argv));
+ {
+ char *p = strchr(*argv, '/');
+ if (p) {
+ local_ns_port =
+ htons((u_int16_t)
+ atoi(p+1));
+ } else {
+ local_ns_port = ns_port;
+ }
+ }
+ break;
+
+#ifdef QRYLOG
+ case 'q':
+ qrylog = 1;
+ break;
+#endif
+
+ case 'r':
+ NoRecurse = 1;
+ break;
+
+ default:
+ usage();
+ }
+ } else
+ bootfile = savestr(*argv);
+ }
+
+#ifdef DEBUG
+ if (!debug)
+#endif
+ for (n = getdtablesize() - 1; n > 2; n--)
+ (void) close(n); /* don't use my_close() here */
+#ifdef DEBUG
+ else {
+ fprintf(ddt, "Debug turned ON, Level %d\n",debug);
+ fprintf(ddt, "Version = %s\n", Version);
+ fprintf(ddt, "bootfile = %s\n", bootfile);
+ }
+#endif
+
+ n = 0;
+#if defined(DEBUG) && defined(LOG_PERROR)
+ if (debug)
+ n = LOG_PERROR;
+#endif
+#ifdef LOG_DAEMON
+ openlog("named", LOG_PID|LOG_CONS|LOG_NDELAY|n, LOGFAC);
+#else
+ openlog("named", LOG_PID);
+#endif
+
+#ifdef WANT_PIDFILE
+ /* tuck my process id away */
+#ifdef PID_FIX
+ fp = fopen(PidFile, "r+");
+ if (fp != NULL) {
+ (void) fgets(oldpid, sizeof(oldpid), fp);
+ (void) rewind(fp);
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#else /*PID_FIX*/
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#endif /*PID_FIX*/
+#endif /*WANT_PIDFILE*/
+
+ syslog(LOG_NOTICE, "starting. %s", Version);
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+
+ nsaddr.sin_family = AF_INET;
+ nsaddr.sin_addr.s_addr = INADDR_ANY;
+ nsaddr.sin_port = local_ns_port;
+
+ /*
+ ** Open stream port.
+ */
+ for (n = 0; ; n++) {
+ if ((vs = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket(SOCK_STREAM): %m");
+ exit(1);
+ }
+ if (setsockopt(vs, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
+ sizeof(on)) != 0)
+ {
+ syslog(LOG_ERR, "setsockopt(vs, reuseaddr): %m");
+ (void) my_close(vs);
+ continue;
+ }
+ if (bind(vs, (struct sockaddr *)&nsaddr, sizeof(nsaddr)) == 0)
+ break;
+
+ if (errno != EADDRINUSE || n > 4) {
+ if (errno == EADDRINUSE) {
+ syslog(LOG_ERR,
+ "There may be a name server already running");
+ syslog(LOG_ERR, "exiting");
+ } else {
+ syslog(LOG_ERR, "bind(vs, [%s].%d): %m",
+ inet_ntoa(nsaddr.sin_addr),
+ ntohs(nsaddr.sin_port));
+ }
+#if defined(WANT_PIDFILE) && defined(PID_FIX)
+ /* put old pid back */
+ if (atoi(oldpid) && (fp = fopen(PidFile, "w"))) {
+ fprintf(fp, "%s", oldpid);
+ (void) my_fclose(fp);
+ _exit(1);
+ }
+#endif /*WANT_PIDFILE && PID_FIX*/
+ exit(1);
+ } else { /* Retry opening the socket a few times */
+ my_close(vs);
+ sleep(1);
+ }
+ }
+ if (listen(vs, 5) != 0) {
+ syslog(LOG_ERR, "listen(vs, 5): %m");
+ exit(1);
+ }
+
+ /*
+ * named would be terminated if one of these is sent and no handler
+ */
+ (void) signal(SIGINT, setdumpflg);
+ (void) signal(SIGQUIT, setchkptflg);
+ (void) signal(SIGIOT, setstatsflg);
+#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 */
+
+#if defined(SIGWINCH) && defined(QRYLOG)
+ (void) signal(SIGWINCH, setQrylogFlg);
+#endif
+
+ /*
+ * 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
+
+ time(&boottime);
+ resettime = boottime;
+
+ (void) signal(SIGHUP, onhup);
+#if defined(SIGXFSZ)
+ (void) signal(SIGXFSZ, onhup); /* wierd DEC Hesiodism, harmless */
+#endif
+#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);
+#ifdef SIGSYS
+ (void) signal(SIGSYS, sigprof);
+#endif /* SIGSYS */
+
+#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
+
+ dprintf(1, (ddt, "database initialized\n"));
+ t.tv_usec = 0;
+
+ /*
+ * Fork and go into background now that
+ * we've done any slow initialization
+ * and are ready to answer queries.
+ */
+#ifdef USE_SETSID
+ if (
+#ifdef DEBUG
+ !debug ||
+#endif
+ !isatty(0)) {
+ if (fork() > 0)
+ exit(0);
+ setsid();
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_close(n);
+ }
+ }
+#else
+#ifdef DEBUG
+ if (!debug)
+#endif
+ {
+#ifdef HAVE_DAEMON
+ daemon(1, 0);
+#else
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit(1);
+ /*FALLTHROUGH*/
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ exit(0);
+ }
+ n = open(_PATH_DEVNULL, O_RDONLY);
+ (void) dup2(n, 0);
+ (void) dup2(n, 1);
+ (void) dup2(n, 2);
+ if (n > 2)
+ (void) my_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) my_close(n);
+ }
+ }
+#endif /* SYSV */
+#endif /* HAVE_DAEMON */
+ }
+#endif /* USE_SETSID */
+#ifdef WANT_PIDFILE
+ /* tuck my process id away again */
+ fp = fopen(PidFile, "w");
+ if (fp != NULL) {
+ fprintf(fp, "%d\n", getpid());
+ (void) my_fclose(fp);
+ }
+#endif
+
+ syslog(LOG_NOTICE, "Ready to answer queries.\n");
+ prime_cache();
+ nfds = getdtablesize(); /* get the number of file descriptors */
+ if (nfds > FD_SETSIZE) {
+ nfds = FD_SETSIZE; /* Bulletproofing */
+ syslog(LOG_ERR, "Return from getdtablesize() > FD_SETSIZE");
+ }
+ FD_ZERO(&mask);
+ FD_SET(vs, &mask);
+ for (dqp = datagramq; dqp != QDATAGRAM_NULL; dqp = dqp->dq_next)
+ FD_SET(dqp->dq_dfd, &mask);
+ for (;;) {
+#ifdef DEBUG
+ if (ddt && debug == 0) {
+ fprintf(ddt,"Debug turned OFF\n");
+ (void) my_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
+ */
+ dprintf(1, (ddt, "Received shutdown signal\n"));
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_CHANGED)
+ zonedump(zp);
+ }
+ exit(0);
+ }
+#endif /* ALLOW_UPDATES */
+ if (needreload) {
+ needreload = 0;
+ db_reload();
+ }
+ if (needStatsDump) {
+ needStatsDump = 0;
+ ns_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);
+ /*
+ ** The tv_sec field might be unsigned
+ ** and thus cannot be negative.
+ */
+ if ((int32_t) retryqp->q_time <= tt.tv_sec) {
+ retry(retryqp);
+ continue;
+ }
+ t.tv_sec = (int32_t) retryqp->q_time - tt.tv_sec;
+ tp = &t;
+ } else
+ tp = NULL;
+ tmpmask = mask;
+ n = select(nfds, &tmpmask, (fd_set *)NULL, (fd_set *)NULL, tp);
+ if (n < 0) {
+ if (errno != EINTR) {
+ syslog(LOG_ERR, "select: %m");
+ sleep(60);
+ }
+ }
+ 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++) { /*XXX*/
+ from_len = sizeof(from_addr);
+ if ((n = recvfrom(dqp->dq_dfd, buf, sizeof(buf), 0,
+ (struct sockaddr *)&from_addr, &from_len)) < 0)
+ {
+ if ((n < 0) && (errno == PORT_WOULDBLK))
+ break;
+ syslog(LOG_WARNING, "recvfrom: %m");
+ break;
+ }
+ if (n == 0)
+ break;
+ gettime(&tt);
+ dprintf(1, (ddt,
+ "\ndatagram from [%s].%d, fd %d, len %d; now %s",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ dqp->dq_dfd, n,
+ ctime(&tt.tv_sec)));
+#ifdef DEBUG
+ 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.
+ **
+ ** Note that a "continue" in here takes us back to the select()
+ ** which, if our accept() failed, will bring us back here.
+ */
+ if (FD_ISSET(vs, &tmpmask)) {
+ from_len = sizeof(from_addr);
+ rfd = accept(vs,
+ (struct sockaddr *)&from_addr,
+ &from_len);
+ if (rfd < 0 && errno == EINTR)
+ continue;
+ if (rfd < 0 && errno == EMFILE && streamq) {
+ maxctime = 0;
+ candidate = NULL;
+ for (sp = streamq; sp; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (sp->s_refcnt)
+ continue;
+ gettime(&tt);
+ lasttime = tt.tv_sec - sp->s_time;
+ if (lasttime >= VQEXPIRY)
+ sqrm(sp);
+ else if (lasttime > maxctime) {
+ candidate = sp;
+ maxctime = lasttime;
+ }
+ }
+ if (candidate)
+ sqrm(candidate);
+ continue;
+ }
+ if (rfd < 0) {
+ syslog(LOG_WARNING, "accept: %m");
+ continue;
+ }
+ if ((n = fcntl(rfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_ERR, "fcntl(rfd, F_GETFL): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (fcntl(rfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_ERR, "fcntl(rfd, NONBLOCK): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+#if defined(IP_OPTIONS)
+ len = sizeof ip_opts;
+ if (getsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ (char *)ip_opts, &len) < 0) {
+ syslog(LOG_ERR,
+ "getsockopt(rfd, IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if (len != 0) {
+ nameserIncr(from_addr.sin_addr, nssRcvdOpts);
+ if (!haveComplained((char*)
+ from_addr.sin_addr.s_addr,
+ "rcvd ip options")) {
+ syslog(LOG_NOTICE,
+ "rcvd IP_OPTIONS from [%s].%d (ignored)",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port));
+ }
+ if (setsockopt(rfd, IPPROTO_IP, IP_OPTIONS,
+ NULL, 0) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt(!IP_OPTIONS): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ }
+#endif
+ if (setsockopt(rfd, SOL_SOCKET, SO_KEEPALIVE,
+ (char *)&on, sizeof(on)) < 0) {
+ syslog(LOG_ERR,
+ "setsockopt(rfd, KEEPALIVE): %m");
+ (void) my_close(rfd);
+ continue;
+ }
+ if ((sp = sqadd()) == QSTREAM_NULL) {
+ (void) my_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 = (u_char *)&sp->s_tempsize;
+ FD_SET(rfd, &mask);
+ FD_SET(rfd, &tmpmask);
+ dprintf(1, (ddt,
+ "\nTCP connection from [%s].%d (fd %d)\n",
+ inet_ntoa(sp->s_from.sin_addr),
+ ntohs(sp->s_from.sin_port), rfd));
+ }
+ if (streamq) {
+ dprintf(3, (ddt, "streamq = 0x%x\n",streamq));
+ }
+ for (sp = streamq; sp != QSTREAM_NULL; sp = nextsp) {
+ nextsp = sp->s_next;
+ if (!FD_ISSET(sp->s_rfd, &tmpmask))
+ continue;
+ dprintf(5, (ddt,
+ "sp x%x rfd %d size %d time %d next x%x\n",
+ sp, sp->s_rfd, sp->s_size,
+ sp->s_time, sp->s_next));
+ dprintf(5, (ddt,
+ "\tbufsize %d buf x%x bufp x%x\n",
+ sp->s_bufsize, sp->s_buf, sp->s_bufp));
+ if (sp->s_size < 0) {
+ size = INT16SZ
+ - (sp->s_bufp - (u_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 < 0) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ if ((sp->s_bufp - (u_char *)&sp->s_tempsize) ==
+ INT16SZ) {
+ sp->s_size = htons(sp->s_tempsize);
+ if (sp->s_bufsize == 0) {
+ if ( (sp->s_buf = (u_char *)
+ malloc(rbufsize))
+ == NULL) {
+ sp->s_buf = buf;
+ sp->s_size = sizeof(buf);
+ } else {
+ sp->s_bufsize = rbufsize;
+ }
+ }
+ if (sp->s_size > sp->s_bufsize &&
+ sp->s_bufsize != 0
+ ) {
+ sp->s_buf = (u_char *)
+ realloc((char *)sp->s_buf,
+ (unsigned)sp->s_size);
+ if (sp->s_buf == 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 > INT16SZ)) {
+ 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,
+ HFIXEDSZ);
+ continue;
+ }
+ if ((n == -1) && (errno == PORT_WOULDBLK))
+ continue;
+ if (n <= 0) {
+ sqrm(sp);
+ continue;
+ }
+ /*
+ * Consult database to get the answer.
+ */
+ if (sp->s_size == 0) {
+ nameserIncr(sp->s_from.sin_addr, nssRcvdTCP);
+ sq_query(sp);
+ ns_req(sp->s_buf,
+ sp->s_bufp - sp->s_buf,
+ sp->s_bufsize, sp,
+ &sp->s_from, -1);
+ /* ns_req() can call sqrm() - check for it */
+ if (sq_here(sp)) {
+ sp->s_bufp = (u_char *)&sp->s_tempsize;
+ sp->s_size = -1;
+ }
+ continue;
+ }
+ }
+ }
+ /* NOTREACHED */
+}
+
+void
+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_int32_t nm;
+ time_t my_generation = time(NULL);
+
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(vs, SIOCGIFCONF, (char *)&ifc) < 0) {
+ syslog(LOG_ERR, "get interface configuration: %m - exiting");
+ exit(1);
+ }
+ ntp = NULL;
+#if defined(AF_LINK) && !defined(RISCOS_BSD)
+#define my_max(a, b) (a > b ? a : b)
+#define my_size(p) my_max((p).sa_len, sizeof(p))
+#else
+#define my_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) + my_size(ifr->ifr_addr)) {
+#undef my_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 !defined(BSD) || (BSD < 199103)
+ if (ioctl(vs, SIOCGIFADDR, (char *)&ifreq) < 0) {
+ syslog(LOG_ERR, "get interface addr: %m");
+ continue;
+ }
+#endif
+ dprintf(1, (ddt, "considering [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+ /* 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.
+ */
+ if (dqp = aIsUs(((struct sockaddr_in *)&ifreq.ifr_addr)
+ ->sin_addr)) {
+ dprintf(1, (ddt,
+ "dup interface address %s on %s\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr),
+ ifreq.ifr_name));
+ dqp->dq_gen = my_generation;
+ continue;
+ }
+
+ /*
+ * Skip over address 0.0.0.0 since this will conflict
+ * with binding to wildcard address later. Interfaces
+ * which are not completely configured can have this addr.
+ */
+ if (((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr
+ == 0x00000000) { /* XXX */
+ dprintf(1, (ddt, "skipping address 0.0.0.0 on %s\n",
+ ifreq.ifr_name));
+ continue;
+ }
+ if ((dqp = (struct qdatagram *)
+ calloc(1, sizeof(struct qdatagram))
+ ) == NULL) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr;
+ dqp->dq_gen = my_generation;
+ opensocket(dqp);
+ dprintf(1, (ddt, "listening [%s]\n",
+ inet_ntoa(((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr)));
+
+ /*
+ * 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 == inet_addr("127.0.0.1")) /* XXX */
+#endif
+ {
+ if (netloop.my_addr.s_addr == 0) {
+ netloop.my_addr = ntp->my_addr;
+ netloop.mask = 0xffffffff;
+ netloop.addr = ntp->my_addr.s_addr;
+ dprintf(1, (ddt, "loopback address: x%lx\n",
+ netloop.my_addr.s_addr));
+ }
+ 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->addr = ((struct sockaddr_in *)
+ &ifreq.ifr_addr)->sin_addr.s_addr;
+ } else {
+ ntp->addr = 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)
+ free((char *)ntp);
+
+ /*
+ * now go through the datagramq and delete anything that
+ * does not have the current generation number. this is
+ * how we catch interfaces that go away or change their
+ * addresses. note that 0.0.0.0 is the wildcard element
+ * and should never be deleted by this code.
+ *
+ * XXX - need to update enettab/elocal as well.
+ */
+ dqflush(my_generation);
+
+ /*
+ * Create separate qdatagram structure for socket
+ * wildcard address.
+ */
+ if (first) {
+ if (!(dqp = (struct qdatagram *)calloc(1, sizeof(*dqp)))) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ dqp->dq_next = datagramq;
+ datagramq = dqp;
+ dqp->dq_addr.s_addr = INADDR_ANY;
+ opensocket(dqp);
+ ds = dqp->dq_dfd;
+ }
+
+ /*
+ * 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) {
+ syslog(LOG_ERR, "getnetconf: malloc: %m");
+ exit(12);
+ }
+ ontp->my_addr = ntp->my_addr;
+ ontp->mask = nm;
+ ontp->addr = 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_int32_t net, mask;
+
+ mask = net_mask(addr);
+ net = addr.s_addr & mask;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+ if (ntp->addr == net && ntp->mask == mask)
+ return (ntp);
+ return ((struct netinfo *) NULL);
+}
+
+#ifdef DEBUG
+static void
+printnetinfo(ntp)
+ register struct netinfo *ntp;
+{
+ for ( ; ntp != NULL; ntp = ntp->next) {
+ fprintf(ddt,"addr x%lx mask x%lx", ntp->addr, ntp->mask);
+ fprintf(ddt," my_addr x%lx", ntp->my_addr.s_addr);
+ fprintf(ddt," %s\n", inet_ntoa(ntp->my_addr));
+ }
+}
+#endif
+
+static void
+opensocket(dqp)
+ register struct qdatagram *dqp;
+{
+ int n, m;
+ 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 - exiting");
+ exit(1);
+ }
+ dprintf(1, (ddt, "dqp->dq_addr %s d_dfd %d\n",
+ inet_ntoa(dqp->dq_addr), dqp->dq_dfd));
+ if (setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&on, sizeof(on)) != 0)
+ {
+ syslog(LOG_ERR, "setsockopt(dqp->dq_dfd, reuseaddr): %m");
+ /* XXX press on regardless, this is not too serious. */
+ }
+#ifdef SO_RCVBUF
+ m = sizeof(n);
+ if ((getsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF, &n, &m) >= 0)
+ && (m == sizeof(n))
+ && (n < rbufsize)) {
+ (void) setsockopt(dqp->dq_dfd, SOL_SOCKET, SO_RCVBUF,
+ (char *)&rbufsize, sizeof(rbufsize));
+ }
+#endif /* SO_RCVBUF */
+ if ((n = fcntl(dqp->dq_dfd, F_GETFL, 0)) < 0) {
+ syslog(LOG_ERR, "fcntl(dfd, F_GETFL): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ } else if (fcntl(dqp->dq_dfd, F_SETFL, n|PORT_NONBLOCK) != 0) {
+ syslog(LOG_ERR, "fcntl(dqp->dq_dfd, non-blocking): %m");
+ /* XXX press on regardless, but this really is a problem. */
+ }
+ /*
+ * 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 - exiting",
+ 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.
+*/
+
+static SIG_FN
+onhup()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGHUP, onhup);
+#endif /* SYSV */
+ needreload = 1;
+ errno = save_errno;
+}
+
+/*
+** Set flag saying to call ns_maint()
+** Must make sure that someone isn't walking through a data
+** structure at the time.
+*/
+
+static SIG_FN
+maint_alarm()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGALRM, maint_alarm);
+#endif /* SYSV */
+ needmaint = 1;
+ errno = save_errno;
+}
+
+
+#ifdef ALLOW_UPDATES
+/*
+ * Signal handler to schedule shutdown. Just set flag, to ensure a consistent
+ * state during dump.
+ */
+static 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
+ */
+static SIG_FN
+setdumpflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGINT, setdumpflg);
+#endif /* SYSV */
+ needToDoadump = 1;
+ errno = save_errno;
+}
+
+/*
+** Turn on or off debuging by open or closeing the debug file
+*/
+
+static void
+setdebug(code)
+ int code;
+{
+#if defined(lint) && !defined(DEBUG)
+ code = code;
+#endif
+#ifdef DEBUG
+
+ if (code) {
+ int n;
+
+ 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
+ if ((n = fcntl(fileno(ddt), F_GETFL, 0)) < 0) {
+ syslog(LOG_WARNING,
+ "fcntl(ddt, F_GETFL): %m");
+ } else {
+ (void) fcntl(fileno(ddt), F_SETFL, n|O_APPEND);
+ }
+ }
+ } 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.
+*/
+
+static SIG_FN
+setIncrDbgFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGUSR1, setIncrDbgFlg);
+#endif /* SYSV */
+#ifdef DEBUG
+ if (debug == 0) {
+ debug++;
+ setdebug(1);
+ } else {
+ debug++;
+ }
+ if (debug)
+ fprintf(ddt, "Debug turned ON, Level %d\n", debug);
+#endif
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal to turn off debugging
+*/
+
+static SIG_FN
+setNoDbgFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGUSR2, setNoDbgFlg);
+#endif /* SYSV */
+ setdebug(0);
+ errno = save_errno;
+}
+
+#if defined(QRYLOG) && defined(SIGWINCH)
+/*
+** Set flag for query logging
+*/
+static SIG_FN
+setQrylogFlg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGWINCH, setQrylogFlg);
+#endif /* SYSV */
+ qrylog = !qrylog;
+ syslog(LOG_NOTICE, "query log %s\n", qrylog ?"on" :"off");
+ errno = save_errno;
+}
+#endif /*QRYLOG && SIGWINCH*/
+
+/*
+** Set flag for statistics dump
+*/
+static SIG_FN
+setstatsflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGIOT, setstatsflg);
+#endif /* SYSV */
+ needStatsDump = 1;
+ errno = save_errno;
+}
+
+static SIG_FN
+setchkptflg()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGQUIT, setchkptflg);
+#endif /* SYSV */
+ needToChkpt = 1;
+ errno = save_errno;
+}
+
+/*
+** Catch a special signal SIGSYS
+**
+** this is setup to fork and exit to drop to /usr/tmp/gmon.out
+** and keep the server running
+*/
+
+#ifdef SIGSYS
+static SIG_FN
+sigprof()
+{
+ int save_errno = errno;
+#if defined(SYSV)
+ (void)signal(SIGSYS, sigprof);
+#endif /* SYSV */
+ dprintf(1, (ddt, "sigprof()\n"));
+ if (fork() == 0)
+ {
+ (void) chdir(_PATH_TMPDIR);
+ exit(1);
+ }
+ errno = save_errno;
+}
+#endif /* SIGSYS */
+
+/*
+** Routines for managing stream queue
+*/
+
+static struct qstream *
+sqadd()
+{
+ register struct qstream *sqp;
+
+ if (!(sqp = (struct qstream *)calloc(1, sizeof(struct qstream)))) {
+ syslog(LOG_ERR, "sqadd: calloc: %m");
+ return (QSTREAM_NULL);
+ }
+ dprintf(3, (ddt, "sqadd(x%x)\n", sqp));
+
+ sqp->s_next = streamq;
+ streamq = sqp;
+ return (sqp);
+}
+
+/* sqrm(qp)
+ * remove stream queue structure `qp'.
+ * no current queries may refer to this stream when it is removed.
+ * side effects:
+ * memory is deallocated. sockets are closed. lists are relinked.
+ */
+void
+sqrm(qp)
+ register struct qstream *qp;
+{
+ register struct qstream *qsp;
+
+ dprintf(2, (ddt, "sqrm(%#x, %d ) rfcnt=%d\n",
+ qp, qp->s_rfd, qp->s_refcnt));
+
+ if (qp->s_bufsize != 0)
+ free(qp->s_buf);
+ FD_CLR(qp->s_rfd, &mask);
+ (void) my_close(qp->s_rfd);
+ if (qp == streamq) {
+ streamq = qp->s_next;
+ } else {
+ for (qsp = streamq;
+ qsp && (qsp->s_next != qp);
+ qsp = qsp->s_next)
+ ;
+ if (qsp) {
+ qsp->s_next = qp->s_next;
+ }
+ }
+ free((char *)qp);
+}
+
+/* void
+ * sqflush(allbut)
+ * call sqrm() on all open streams except `allbut'
+ * side effects:
+ * global list `streamq' modified
+ * idiocy:
+ * is N^2 due to the scan inside of sqrm()
+ */
+void
+sqflush(allbut)
+ register struct qstream *allbut;
+{
+ register struct qstream *sp, *spnext;
+
+ for (sp = streamq; sp != NULL; sp = spnext) {
+ spnext = sp->s_next;
+ if (sp != allbut)
+ sqrm(sp);
+ }
+}
+
+/* void
+ * dqflush(gen)
+ * close/deallocate all the udp sockets, unless `gen' != (time_t)0
+ * in which case all those not matching this generation will
+ * be deleted except the 0.0.0.0 element, and syslog() will
+ * be called whenever something is deleted.
+ * side effects:
+ * global list `datagramq' is modified
+ */
+void
+dqflush(gen)
+ register time_t gen;
+{
+ register struct qdatagram *dqp, *pqp, *nqp;
+
+ for (pqp = NULL, dqp = datagramq;
+ dqp != NULL;
+ pqp = dqp, dqp = nqp) {
+ nqp = dqp->dq_next;
+ if (gen != (time_t)0) {
+ if (dqp->dq_addr.s_addr == INADDR_ANY ||
+ dqp->dq_gen == gen)
+ continue;
+ syslog(LOG_CRIT, "interface [%s] missing; deleting",
+ inet_ntoa(dqp->dq_addr));
+ }
+ if (pqp != NULL)
+ pqp->dq_next = dqp->dq_next;
+ else
+ datagramq = dqp->dq_next;
+ free(dqp);
+ }
+}
+
+/* int
+ * sq_here(sp)
+ * determine whether stream 'sp' is still on the streamq
+ * return:
+ * boolean: is it here?
+ */
+static int
+sq_here(sp)
+ register struct qstream *sp;
+{
+ register struct qstream *t;
+
+ for (t = streamq; t != NULL; t = t->s_next)
+ if (t == sp)
+ return (1);
+ return (0);
+}
+
+/*
+ * Initiate query on stream;
+ * mark as referenced and stop selecting for input.
+ */
+static void
+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.
+ */
+void
+sq_done(sp)
+ register struct qstream *sp;
+{
+
+ sp->s_refcnt = 0;
+ sp->s_time = tt.tv_sec;
+ FD_SET(sp->s_rfd, &mask);
+}
+
+void
+ns_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_int32_t
+net_mask(in)
+ struct in_addr in;
+{
+ register u_int32_t 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));
+}
+
+#if defined(BSD43_BSD43_NFS)
+/* junk needed for old Sun NFS licensees */
+#undef dn_skipname
+extern char *dn_skipname();
+char *(*hack_skipname)() = dn_skipname;
+#endif
diff --git a/usr.sbin/named/ns_maint.c b/usr.sbin/named/ns_maint.c
new file mode 100644
index 0000000..927fde3
--- /dev/null
+++ b/usr.sbin/named/ns_maint.c
@@ -0,0 +1,784 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_maint.c 4.39 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: ns_maint.c,v 4.9.1.15 1994/06/11 22:04:46 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#include "named.h"
+
+#ifdef USE_UTIME
+# include <utime.h>
+#endif
+
+static int xfers_running, /* # of xfers running */
+ xfers_deferred, /* # of needed xfers not run yet */
+ qserials_running,
+ alarm_pending, /* flag */
+ nxfers __P((struct zoneinfo *, int));
+
+static void startxfer __P((struct zoneinfo *)),
+ abortxfer __P((struct zoneinfo *)),
+ addxfer __P((struct zoneinfo *)),
+ qserial_query __P((struct zoneinfo *)),
+ tryxfer __P((void));
+
+#define qserial_qfull() (qserials_running == MAXQSERIAL)
+
+#ifdef CLEANCACHE
+static time_t cache_time;
+#endif
+/*
+ * 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.
+ */
+void
+ns_maint()
+{
+ register struct zoneinfo *zp;
+ int zonenum;
+
+ gettime(&tt);
+
+ dprintf(1, (ddt, "\nns_maint(); now %s", ctime(&tt.tv_sec)));
+
+ 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) {
+ switch (zp->z_type) {
+
+ case Z_CACHE:
+ doachkpt();
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ break;
+
+ case Z_SECONDARY:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ if (zp->z_flags &
+ (Z_NEED_RELOAD|Z_NEED_XFER|Z_QSERIAL)) {
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ break;
+ }
+ if (zp->z_flags & Z_XFER_RUNNING) {
+ abortxfer(zp);
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+ }
+ qserial_query(zp);
+ break;
+#ifdef ALLOW_UPDATES
+ case Z_PRIMARY:
+ /*
+ * Checkpoint the zone if it has changed
+ * since we last checkpointed
+ */
+ if (zp->z_flags & Z_CHANGED) {
+ zonedump(zp);
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ }
+ break;
+#endif /* ALLOW_UPDATES */
+ }
+ gettime(&tt);
+ }
+ }
+#ifdef CLEANCACHE
+ remove_zone(hashtab, 0, 0);
+#endif
+ if (!needmaint)
+ sched_maint();
+ dprintf(1, (ddt, "exit ns_maint()\n"));
+}
+
+/*
+ * Find when the next refresh needs to be and set
+ * interrupt time accordingly.
+ */
+void
+sched_maint()
+{
+ register struct zoneinfo *zp;
+ struct itimerval ival;
+#ifdef CLEANCACHE
+ time_t next_refresh = cache_time + 3600;
+#else
+ time_t next_refresh = 0;
+#endif
+ 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) {
+ dprintf(1, (ddt, "sched_maint: no schedule change\n"));
+ return;
+ }
+ /*
+ * tv_sec can be an unsigned long, so we can't let
+ * it go negative.
+ */
+ if (next_refresh < tt.tv_sec)
+ next_refresh = tt.tv_sec;
+ ival.it_value.tv_sec = next_refresh - tt.tv_sec;
+ if ((long) 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);
+ dprintf(1, (ddt, "sched_maint: Next interrupt in %d sec\n",
+ ival.it_value.tv_sec));
+}
+
+/*
+ * Mark a zone "up to date" after named-xfer tells us this or we
+ * discover it through the qserial_*() logic.
+ */
+static void
+markUpToDate(zp)
+ struct zoneinfo *zp;
+{
+ struct stat f_time;
+
+ zp->z_flags &= ~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_flags & Z_DB_BAD) == 0)
+ zp->z_flags |= Z_AUTH;
+ if (zp->z_source) {
+#if defined(USE_UTIME)
+ 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 /* USE_UTIME */
+ }
+ /* we use "stat" to set zp->z_ftime instead of just
+ setting it to tt.tv_sec in order to avoid any
+ possible rounding problems in utimes(). */
+ if (stat(zp->z_source, &f_time) != -1)
+ zp->z_ftime = f_time.st_mtime;
+ /* XXX log if stat fails? XXX */
+}
+
+/*
+ * Query for the serial number of a zone, so that
+ * we can check to see if we need to transfer it.
+ */
+static void
+qserial_query(zp)
+ struct zoneinfo *zp;
+{
+ struct qinfo *qp;
+
+ dprintf(1, (ddt, "qserial_query(%s)\n", zp->z_origin));
+
+ if (qserial_qfull())
+ return;
+
+ qp = sysquery(zp->z_origin, zp->z_class, T_SOA,
+ zp->z_addr, zp->z_addrcnt);
+ if (!qp) {
+ dprintf(1, (ddt, "qserial_query(%s) FAILED\n", zp->z_origin));
+ return; /* XXX - this is bad, we should do something */
+ }
+ qp->q_flags |= Q_ZSERIAL;
+ qp->q_zquery = zp;
+ zp->z_flags |= Z_QSERIAL;
+ zp->z_time = tt.tv_sec + zp->z_refresh;
+ qserials_running++;
+ dprintf(1, (ddt, "qserial_query(%s) QUEUED\n", zp->z_origin));
+}
+
+void
+qserial_answer(qp, serial)
+ struct qinfo *qp;
+ u_int32_t serial;
+{
+ struct zoneinfo *zp = qp->q_zquery;
+ int was_qfull = qserial_qfull();
+
+ dprintf(1, (ddt, "qserial_answer(%s, %lu)\n", zp->z_origin, serial));
+ zp->z_flags &= ~Z_QSERIAL;
+ qp->q_flags &= ~Q_ZSERIAL; /* keeps us from being called twice */
+ qserials_running--;
+ if (serial == 0) {
+ /* an error occurred, or the query timed out.
+ */
+#ifdef GETSER_LOGGING
+ syslog(GETSER_LOGGING, "Err/TO getting serial# for \"%s\"",
+ zp->z_origin);
+#endif /* GETSER_LOGGING */
+ addxfer(zp);
+ } else if (SEQ_GT(serial, zp->z_serial) || !zp->z_serial) {
+ dprintf(1, (ddt, "qserial_answer: zone is out of date\n"));
+ zp->z_xaddr = from_addr.sin_addr; /* don't use qp->q_from */
+ addxfer(zp);
+ } else if (SEQ_GT(zp->z_serial, serial)) {
+ if (!haveComplained((char*)zp, "went backward")) {
+ syslog(LOG_NOTICE,
+ "Zone \"%s\" (class %d) SOA serial# (%lu) rcvd from [%s] is < ours (%lu)\n",
+ zp->z_origin, zp->z_class, serial,
+ inet_ntoa(from_addr.sin_addr),
+ zp->z_serial);
+ }
+ } else {
+ dprintf(1, (ddt, "qserial_answer: zone serial is still OK\n"));
+ markUpToDate(zp);
+ }
+ done:
+ if (was_qfull)
+ needmaint = 1;
+}
+
+/*
+ * Start an asynchronous zone transfer for a zone.
+ * Depends on current time being in tt.
+ * The caller must call sched_maint after startxfer.
+ */
+static void
+startxfer(zp)
+ struct zoneinfo *zp;
+{
+ static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
+ int argc = 0, argc_ns = 0, pid, omask;
+ unsigned int cnt;
+ char debug_str[10];
+ char serial_str[10];
+ char port_str[10];
+#ifdef GEN_AXFR
+ char class_str[10];
+#endif
+
+ dprintf(1, (ddt, "startxfer() %s\n", zp->z_origin));
+
+ 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, "%lu", zp->z_serial);
+ argv[argc++] = serial_str;
+#ifdef GEN_AXFR
+ argv[argc++] = "-C";
+ sprintf(class_str, "%d", zp->z_class);
+ argv[argc++] = class_str;
+#endif
+ if (zp->z_flags & Z_SYSLOGGED)
+ argv[argc++] = "-q";
+ argv[argc++] = "-P";
+ sprintf(port_str, "%d", ns_port);
+ argv[argc++] = port_str;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ argv[argc++] = "-S";
+#endif
+#ifdef DEBUG
+ if (debug) {
+ argv[argc++] = "-d";
+ sprintf(debug_str, "%d", debug);
+ argv[argc++] = debug_str;
+ argv[argc++] = "-l";
+ argv[argc++] = _PATH_XFERDDT;
+ if (debug > 5) {
+ argv[argc++] = "-t";
+ argv[argc++] = _PATH_XFERTRACE;
+ }
+ }
+#endif
+
+ if (zp->z_xaddr.s_addr != 0) {
+ /* address was specified by the qserial logic, use it */
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(zp->z_xaddr));
+ } else {
+ /*
+ * 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++) {
+ struct in_addr a;
+
+ a = zp->z_addr[cnt];
+ if (aIsUs(a)
+ && !haveComplained(zp->z_origin,
+ (char*)startxfer)) {
+ syslog(LOG_ERR,
+ "attempted to fetch zone %s from self (%s)",
+ zp->z_origin, inet_ntoa(a));
+ continue;
+ }
+ argv[argc++] = strcpy(argv_ns[argc_ns++],
+ inet_ntoa(a));
+ }
+ }
+
+ 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) {
+ syslog(LOG_ERR, "xfer vfork: %m");
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+ zp->z_time = tt.tv_sec + 10;
+ return;
+ }
+
+ if (pid == 0) {
+ /* child */
+ execv(_PATH_XFER, argv);
+ syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
+ _exit(XFER_FAIL); /* avoid duplicate buffer flushes */
+ }
+ /* parent */
+ dprintf(1, (ddt, "started xfer child %d\n", pid));
+ zp->z_flags &= ~Z_NEED_XFER;
+ zp->z_flags |= Z_XFER_RUNNING;
+ zp->z_xferpid = pid;
+ xfers_running++;
+ zp->z_time = tt.tv_sec + MAX_XFER_TIME;
+#ifndef SYSV
+ (void) sigsetmask(omask);
+#endif
+}
+
+#ifdef DEBUG
+void
+printzoneinfo(zonenum)
+int zonenum;
+{
+ struct timeval tt;
+ struct zoneinfo *zp = &zones[zonenum];
+ char *ZoneType;
+
+ if (!debug)
+ return;
+
+ fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
+
+ gettime(&tt);
+ switch (zp->z_type) {
+ case Z_PRIMARY:
+ ZoneType = "Primary";
+ break;
+ case Z_SECONDARY:
+ ZoneType = "Secondary";
+ break;
+#ifdef STUBS
+ case Z_STUB:
+ ZoneType = "Stub";
+ break;
+#endif
+ case Z_CACHE:
+ ZoneType = "Cache";
+ break;
+ default:
+ ZoneType = "Unknown";
+ break;
+ }
+ if (zp->z_origin != NULL && (zp->z_origin[0] == '\0'))
+ fprintf(ddt, "origin ='.'");
+ else
+ fprintf(ddt, "origin ='%s'", zp->z_origin);
+#ifdef GEN_AXFR
+ fprintf(ddt, ", class = %d", zp->z_class);
+#endif
+ fprintf(ddt, ", type = %s", ZoneType);
+ if (zp->z_source)
+ 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 = %lu\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, "; flags %x\n", zp->z_flags);
+}
+#endif /* DEBUG */
+
+/*
+ * remove_zone (htp, zone) --
+ * Delete all RR's in the zone "zone" under specified hash table.
+ */
+void
+#ifdef CLEANCACHE
+remove_zone(htp, zone, all)
+#else
+remove_zone(htp, zone)
+#endif
+ register struct hashbuf *htp;
+ register int zone;
+#ifdef CLEANCACHE
+ register int all;
+#endif
+{
+ register struct databuf *dp, *pdp;
+ register struct namebuf *np, *pnp, *npn;
+ struct namebuf **npp, **nppend;
+
+ nppend = htp->h_tab + htp->h_size;
+ for (npp = htp->h_tab; npp < nppend; npp++)
+ for (pnp = NULL, np = *npp; np != NULL; np = npn) {
+ for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
+#ifdef CLEANCACHE
+ if (dp->d_zone == zone && (all || stale(dp)))
+#else
+ if (dp->d_zone == zone)
+#endif
+ dp = rm_datum(dp, np, pdp);
+ else {
+ pdp = dp;
+ dp = dp->d_next;
+ }
+ }
+
+ if (np->n_hash) {
+ /* call recursively to remove subdomains. */
+#ifdef CLEANCACHE
+ remove_zone(np->n_hash, zone, all);
+#else
+ remove_zone(np->n_hash, zone);
+#endif
+
+ /* if now empty, free it */
+ if (np->n_hash->h_cnt == 0) {
+ free((char*)np->n_hash);
+ np->n_hash = NULL;
+ }
+ }
+
+ if ((np->n_hash == NULL) && (np->n_data == NULL)) {
+ npn = rm_name(np, npp, pnp);
+ htp->h_cnt--;
+ } else {
+ npn = np->n_next;
+ pnp = np;
+ }
+ }
+}
+
+/*
+ * Handle XFER limit for a nameserver.
+ */
+static int
+nxfers(zp, delta)
+ struct zoneinfo *zp;
+ int delta;
+{
+ struct in_addr nsa;
+ struct nameser *nsp;
+ int ret;
+
+ if (zp->z_xaddr.s_addr)
+ nsa = zp->z_xaddr; /* qserial overrode address */
+ else if (!zp->z_addrcnt)
+ return (-1);
+ else
+ nsa = zp->z_addr[0]; /* first ns holds zone's xfer limit */
+
+ if (!(nsp = nameserFind(nsa, NS_F_INSERT)))
+ return (-1); /* probably ENOMEM */
+
+ ret = nsp->xfers;
+ if (delta < 0 && -delta > ret)
+ return (-1); /* taking more than we have */
+
+ nsp->xfers += delta;
+ return (ret);
+}
+
+/*
+ * Abort an xfer that has taken too long.
+ */
+static void
+abortxfer(zp)
+ struct zoneinfo *zp;
+{
+ kill(zp->z_xferpid, SIGKILL);
+ syslog(LOG_NOTICE, "zone transfer timeout for \"%s\"; pid %lu killed",
+ zp->z_origin, (u_long)zp->z_xferpid);
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ (void) nxfers(zp, -1);
+ xfers_running--;
+}
+
+/*
+ * SIGCHLD signal handler: process exit of xfer's.
+ * (Note: also called when outgoing transfer completes.)
+ */
+SIG_FN
+endxfer()
+{
+ register struct zoneinfo *zp;
+ int exitstatus, pid, xfers, save_errno;
+#if defined(sequent)
+ union wait status;
+#else
+ int status;
+#endif /* sequent */
+
+ save_errno = errno;
+ xfers = 0;
+ gettime(&tt);
+#if defined(USE_WAITPID)
+ while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
+#else /* USE_WAITPID */
+ {
+ pid = wait(&status);
+#endif /* USE_WAITPID */
+ exitstatus = WIFEXITED(status) ?WEXITSTATUS(status) :0;
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_xferpid != pid)
+ continue;
+ xfers++;
+ xfers_running--;
+ (void) nxfers(zp, -1);
+ zp->z_xferpid = 0;
+ zp->z_flags &= ~Z_XFER_RUNNING;
+ dprintf(1, (ddt,
+ "\nendxfer: child %d zone %s returned status=%d termsig=%d\n",
+ pid, zp->z_origin, exitstatus,
+ WIFSIGNALED(status) ?WTERMSIG(status) :-1
+ )
+ );
+ if (WIFSIGNALED(status)) {
+ if (WTERMSIG(status) != SIGKILL) {
+ syslog(LOG_NOTICE,
+ "named-xfer exited with signal %d\n",
+ WTERMSIG(status));
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ } else {
+ switch (exitstatus) {
+ case XFER_UPTODATE:
+ markUpToDate(zp);
+ break;
+
+ case XFER_SUCCESS:
+ zp->z_flags |= Z_NEED_RELOAD;
+ zp->z_flags &= ~Z_SYSLOGGED;
+ needzoneload++;
+ break;
+
+ case XFER_TIMEOUT:
+ dprintf(1, (ddt,
+ "zoneref: Masters for secondary zone %s unreachable\n",
+ zp->z_origin));
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ syslog(LOG_NOTICE,
+ "zoneref: Masters for secondary zone %s unreachable",
+ zp->z_origin);
+ }
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+
+ default:
+ if (!(zp->z_flags & Z_SYSLOGGED)) {
+ zp->z_flags |= Z_SYSLOGGED;
+ syslog(LOG_NOTICE,
+ "named-xfer for %s exited %d",
+ zp->z_origin, exitstatus);
+ }
+ /* FALLTHROUGH */
+ case XFER_FAIL:
+ zp->z_flags |= Z_SYSLOGGED;
+ zp->z_time = tt.tv_sec + zp->z_retry;
+ break;
+ } /*switch*/
+ break;
+ } /*if/else*/
+ } /*for*/
+ } /*while*/
+ tryxfer();
+#if defined(SYSV)
+ (void)signal(SIGCLD, endxfer);
+#endif
+ errno = save_errno;
+}
+
+/*
+ * Try to start some xfers
+ */
+static void
+tryxfer() {
+ struct zoneinfo *zp;
+
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ int xfers;
+
+ if (!xfers_deferred || xfers_running >= max_xfers_running)
+ break;
+
+ if ((xfers = nxfers(zp, 0)) != -1 &&
+ xfers < MAX_XFERS_PERNS &&
+ (zp->z_flags & Z_NEED_XFER)) {
+ nxfers(zp, 1);
+ xfers_deferred--;
+ startxfer(zp);
+ }
+ }
+ if (!needmaint)
+ sched_maint();
+}
+
+/*
+ * Reload zones whose transfers have completed.
+ */
+void
+loadxfer()
+{
+ register struct zoneinfo *zp;
+
+ gettime(&tt);
+ for (zp = zones; zp < &zones[nzones]; zp++) {
+ if (zp->z_flags & Z_NEED_RELOAD) {
+ dprintf(1, (ddt, "loadxfer() \"%s\"\n",
+ zp->z_origin[0] ? zp->z_origin : "."));
+ zp->z_flags &= ~(Z_NEED_RELOAD|Z_AUTH);
+#ifdef CLEANCACHE
+ remove_zone(hashtab, zp - zones, 1);
+#else
+ remove_zone(hashtab, zp - zones);
+#endif
+ if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
+ zp->z_flags |= Z_AUTH;
+ if (zp->z_flags & Z_TMP_FILE)
+ (void) unlink(zp->z_source);
+ syslog(LOG_INFO,
+ "Zone \"%s\" (class %d) xfer'd and loaded (serial %lu)",
+ zp->z_origin, zp->z_class, zp->z_serial);
+ }
+ }
+ if (!needmaint)
+ sched_maint();
+}
+
+/*
+ * Add this zone to the set of those needing transfers.
+ */
+static void
+addxfer(zp)
+ struct zoneinfo *zp;
+{
+ if (!(zp->z_flags & Z_NEED_XFER)) {
+ zp->z_flags |= Z_NEED_XFER;
+ xfers_deferred++;
+ tryxfer();
+ }
+}
diff --git a/usr.sbin/named/ns_ncache.c b/usr.sbin/named/ns_ncache.c
new file mode 100644
index 0000000..5408342
--- /dev/null
+++ b/usr.sbin/named/ns_ncache.c
@@ -0,0 +1,152 @@
+/**************************************************************************
+ * ns_ncache.c
+ * author: anant kumar
+ * last modification: March 17, 1993
+ *
+ * implements negative caching
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+#ifdef NCACHE
+
+void
+cache_n_resp(msg, msglen)
+ u_char *msg;
+ int msglen;
+{
+ register struct databuf *dp;
+ HEADER *hp;
+ u_char *cp;
+ char dname[MAXDNAME];
+ int n;
+ int type, class;
+ int Vcode;
+ int flags;
+
+ nameserIncr(from_addr.sin_addr, nssRcvdNXD);
+
+ hp = (HEADER *)msg;
+ cp = msg+HFIXEDSZ;
+
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ dprintf(1, (ddt, "Query expand name failed:cache_n_resp\n"));
+ hp->rcode = FORMERR;
+ return;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ dprintf(1, (ddt,
+ "ncache: dname %s, type %d, class %d\n",
+ dname, type, class));
+
+#ifdef VALIDATE
+ Vcode = validate(dname, &from_addr, type, class, NULL, 0,
+ hp->rcode == NXDOMAIN ? NXDOMAIN : NOERROR_NODATA);
+ if (Vcode == INVALID || Vcode == VALID_NO_CACHE) {
+ /*Valid_no_cache should never occur but doesn't hurt to check*/
+ return;
+ }
+#endif
+#ifdef RETURNSOA
+ if (hp->rcode==NXDOMAIN) {
+ u_int32_t ttl;
+ u_int16_t atype;
+ u_char * tp = cp;
+ u_char * cp1;
+ u_char data[BUFSIZ+MAXDNAME];
+ int len = sizeof(data);
+
+ /* store ther SOA record */
+ if (!hp->nscount) {
+ dprintf(3, (ddt, "ncache: nscount == 0\n"));
+ return;
+ }
+ n = dn_skipname(tp, msg + msglen);
+ if (n < 0) {
+ dprintf(3, (ddt, "ncache: form error\n"));
+ return;
+ }
+ tp += n;
+ GETSHORT(atype,tp); /* type */
+ if (atype != T_SOA) {
+ dprintf(3, (ddt, "ncache: type (%d) != T_SOA\n",atype));
+ return;
+ }
+ tp += sizeof(u_int16_t); /* class */
+ GETLONG(ttl,tp); /* ttl */
+ tp += sizeof(u_int16_t); /* dlen */
+
+ if ((n = dn_expand(msg, msg + msglen, tp, data, len))
+ < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ } /* origin */
+ tp += n;
+ cp1 = data + (n = strlen(data) + 1);
+ len -= n;
+ if ((n = dn_expand(msg, msg + msglen, tp, cp1, len)) < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ } /* mail */
+ tp += n;
+ n = strlen(cp1) + 1;
+ cp1 += n;
+ len -= n;
+ bcopy(tp, cp1, n = 5 * sizeof(u_int32_t));
+ /* serial, refresh, retry, expire, min */
+ cp1 += n;
+ len -= n;
+ /* store the zone of the soa record */
+ if ((n = dn_expand(msg, msg + msglen, cp, cp1, len)) < 0 ) {
+ dprintf(3, (ddt, "ncache: form error 2\n"));
+ return;
+ }
+ n = strlen(cp1) + 1;
+ cp1 += n;
+
+ dp = savedata(class, T_SOA, MIN(ttl,NTTL)+tt.tv_sec, data,
+ cp1 - data);
+ } else {
+#endif
+ dp = savedata(class, type, NTTL+tt.tv_sec, NULL, 0);
+#ifdef RETURNSOA
+ }
+#endif
+ dp->d_zone = DB_Z_CACHE;
+ dp->d_cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
+ dp->d_clev = 0;
+ if(hp->rcode == NXDOMAIN) {
+ dp->d_rcode = NXDOMAIN;
+ flags = DB_NODATA|DB_NOTAUTH|DB_NOHINTS;
+ } else {
+ dp->d_rcode = NOERROR_NODATA;
+ flags = DB_NOTAUTH|DB_NOHINTS;
+ }
+
+ if ((n = db_update(dname,dp,dp,flags,hashtab)) != OK) {
+ dprintf(1, (ddt,
+ "db_update failed return value:%d, cache_n_resp()\n",
+ n));
+ free((char *)dp);
+ return;
+ }
+ dprintf(4, (ddt,
+ "ncache succeeded: d:%s, t:%d, c:%d rcode:%d ttl:%d\n",
+ dname,type,class,dp->d_rcode, dp->d_ttl-tt.tv_sec));
+ return;
+}
+
+#endif /*NCACHE*/
diff --git a/usr.sbin/named/ns_req.c b/usr.sbin/named/ns_req.c
new file mode 100644
index 0000000..afc3fc5
--- /dev/null
+++ b/usr.sbin/named/ns_req.c
@@ -0,0 +1,1793 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_req.c 4.47 (Berkeley) 7/1/91";
+static char rcsid[] = "$Id: ns_req.c,v 4.9.1.22 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+struct addinfo {
+ char *a_dname; /* domain name */
+ u_int a_class; /* class for address */
+};
+
+enum req_action { Finish, Refuse, Return };
+
+static enum req_action req_query __P((HEADER *hp, u_char **cpp, u_char *eom,
+ struct qstream *qsp,
+ int *buflenp, int *msglenp,
+ u_char *msg, int dfd,
+ struct sockaddr_in *from));
+
+#ifdef INVQ
+static enum req_action req_iquery __P((HEADER *hp, u_char **cpp, u_char *eom,
+ int *buflenp, u_char *msg,
+ struct sockaddr_in *from));
+#endif
+
+static void fwritemsg __P((FILE *, u_char *, int)),
+ doaxfr __P((struct namebuf *, FILE *,
+ struct namebuf *, int)),
+ startxfr __P((struct qstream *, struct namebuf *,
+ u_char *, int, int, const char *)),
+ printSOAdata __P((struct databuf));
+
+#ifdef ALLOW_UPDATES
+static int InitDynUpdate __P((register HEADER *hp,
+ char *msg,
+ int msglen,
+ u_char *startcp,
+ struct sockaddr_in *from,
+ struct qstream *qsp,
+ int dfd));
+#endif
+
+static struct addinfo addinfo[NADDRECS];
+static void addname __P((char *, u_int16_t));
+
+/*
+ * Process request using database; assemble and send response.
+ */
+void
+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 = (HEADER *) msg;
+ u_char *cp, *eom;
+ enum req_action action;
+
+#ifdef DEBUG
+ if (debug > 3) {
+ fprintf(ddt, "ns_req(from=[%s].%d)\n",
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+ fp_query(msg, ddt);
+ }
+#endif
+
+ /*
+ * XXX - this decision should be made by our caller, not by us.
+ */
+ if (hp->qr) {
+ ns_resp(msg, msglen);
+
+ /* Now is a safe time for housekeeping */
+ if (needs_prime_cache)
+ prime_cache();
+
+ return;
+ }
+
+ /* its a query and these bits have no business
+ * being set. will later simplify work if we can
+ * safely assume these are always 0 when a query
+ * comes in
+ */
+ hp->aa = hp->ra = 0;
+
+ hp->rcode = NOERROR;
+ cp = msg + HFIXEDSZ;
+ eom = msg + msglen;
+
+ dnptrs[0] = msg;
+ dnptrs[1] = NULL;
+
+ free_addinfo(); /* sets addcount to zero */
+ dnptrs[0] = NULL;
+
+ switch (hp->opcode) {
+ case QUERY:
+ action = req_query(hp, &cp, eom, qsp,
+ &buflen, &msglen,
+ msg, dfd, from);
+ break;
+
+#ifdef INVQ
+ case IQUERY:
+ action = req_iquery(hp, &cp, eom, &buflen, msg, from);
+ break;
+#endif
+
+#ifdef ALLOW_UPDATES
+#define FORWARDED 1000
+/*
+ * 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)
+ */
+ /* Call InitDynUpdate for all dynamic update requests */
+ case UPDATEM:
+ case UPDATEMA:
+ case UPDATED:
+ case UPDATEDA:
+ case UPDATEA:
+ n = InitDynUpdate(hp, msg, msglen, cp, from, qsp, dfd);
+ if (n == FORWARDED) {
+ /* Return directly because InitDynUpdate
+ * forwarded the query to the primary, so we
+ * will send response later
+ */
+ action = Return;
+ } else {
+ /* Either sucessful primary update or failure;
+ * return response code to client
+ */
+ action = Finish;
+ }
+#endif /* ALLOW_UPDATES */
+
+ case ZONEREF:
+ dprintf(1, (ddt, "Refresh Zone\n"));
+ /*FALLTHROUGH*/
+
+ default:
+ dprintf(1, (ddt, "ns_req: Opcode %d not implemented\n",
+ hp->opcode));
+ /* XXX - should syslog, limited by haveComplained */
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = NOTIMP;
+ action = Finish;
+ }
+
+ /*
+ * vector via internal opcode. (yes, it was even uglier before.)
+ */
+ switch (action) {
+ case Return:
+ return;
+ case Refuse:
+ hp->rcode = REFUSED;
+ /*FALLTHROUGH*/
+ case Finish:
+ /* rest of the function handles this case */
+ break;
+ default:
+ syslog(LOG_CRIT, "bad action variable in ns_req() -- %d",
+ (int) action);
+ return; /* XXX - should really exit here */
+ }
+
+ /*
+ * apply final polish
+ */
+ hp->qr = 1; /* set Response flag */
+ if (NoRecurse)
+ hp->ra = 0; /* No recursion; maybe we're a root server */
+ else
+ hp->ra = 1; /* Recursion is Available */
+ hp->ancount = htons(hp->ancount);
+ if (addcount) {
+ int n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+
+ dprintf(1, (ddt, "ns_req: answer -> [%s].%d fd=%d id=%d %s\n",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ (qsp == QSTREAM_NULL) ?dfd :qsp->s_rfd,
+ ntohs(hp->id), local(from) == NULL ? "Remote" : "Local"));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (qsp == QSTREAM_NULL) {
+ if (sendto(dfd, msg, cp - msg, 0,
+ (struct sockaddr *)from,
+ sizeof(*from)) < 0) {
+ if (!haveComplained((char*)from->sin_addr.s_addr,
+ sendtoStr))
+ syslog(LOG_NOTICE,
+ "ns_req: sendto([%s].%d): %m",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ nameserIncr(from->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(from->sin_addr, nssSentAns);
+ } else {
+ (void) writemsg(qsp->s_rfd, msg, cp - msg);
+ sq_done(qsp);
+ }
+
+ if (needs_prime_cache) {
+ prime_cache(); /* Now is a safe time */
+ }
+}
+
+static enum req_action
+req_query(hp, cpp, eom, qsp, buflenp, msglenp, msg, dfd, from)
+ HEADER *hp;
+ u_char **cpp;
+ u_char *eom;
+ struct qstream *qsp;
+ u_char *msg;
+ int *buflenp, *msglenp, dfd;
+ struct sockaddr_in *from;
+{
+ int n, class, type, count, foundname, founddata, omsglen, cname;
+ u_int16_t id;
+ u_char **dpp, *omsg, *answers;
+ char dnbuf[MAXDNAME], *dname, *fname;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ struct namebuf *np;
+ struct qinfo *qp;
+ struct netinfo *lp;
+
+ nameserIncr(from->sin_addr, nssRcvdQ);
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+
+ dpp = dnptrs;
+ *dpp++ = msg;
+ *dpp = NULL;
+
+ /* valid queries have one question and zero answers */
+ if ((ntohs(hp->qdcount) != 1)
+ || hp->ancount
+ || hp->nscount
+ || hp->arcount) {
+ dprintf(1, (ddt, "FORMERR Query header counts wrong\n"));
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * Get domain name, class, and type.
+ */
+ if ((**cpp & INDIR_MASK) == 0) {
+ *dpp++ = *cpp; /* remember name for compression */
+ }
+ *dpp = NULL;
+ n = dn_expand(msg, eom, *cpp, dnbuf, sizeof dnbuf);
+ if (n < 0) {
+ dprintf(1, (ddt, "FORMERR Query expand name failed\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ if (*cpp > eom) {
+ dprintf(1, (ddt, "FORMERR Query message length short\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ if (*cpp < eom) {
+ dprintf(6, (ddt,"message length > received message\n"));
+ *msglenp = *cpp - msg;
+ }
+
+ qtypeIncr(type);
+
+ /*
+ * Process query.
+ */
+ if (type == T_AXFR) {
+ /* refuse request if not a TCP connection */
+ if (qsp == QSTREAM_NULL) {
+ syslog(LOG_INFO,
+ "rejected UDP AXFR from [%s].%u for \"%s\"",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ return (Refuse);
+ }
+ /* the position of this is subtle. */
+ nameserIncr(from->sin_addr, nssRcvdAXFR);
+#ifdef XFRNETS
+ if (xfrnets) {
+ /* if xfrnets was specified, peer address
+ * must be on it. should probably allow
+ * for negation some day.
+ */
+ if (!addr_on_netlist(from->sin_addr, xfrnets)) {
+ syslog(LOG_INFO,
+ "unapproved AXFR from [%s].%u for %s",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ return (Refuse);
+ }
+ }
+#endif /*XFRNETS*/
+ dnptrs[0] = NULL; /* don't compress names */
+ hp->rd = 0; /* recursion not possible */
+ syslog(LOG_INFO, "approved AXFR from [%s].%d for \"%s\"",
+ inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port),
+ *dnbuf ? dnbuf : ".");
+ }
+ *buflenp -= *msglenp;
+ count = 0;
+ foundname = 0;
+ founddata = 0;
+ dname = dnbuf;
+ cname = 0;
+
+#ifdef QRYLOG
+ if (qrylog) {
+ syslog(LOG_INFO, "XX /%s/%s/%s",
+ inet_ntoa(from->sin_addr),
+ (dname[0] == '\0') ?"." :dname,
+ p_type(type));
+ }
+#endif /*QRYLOG*/
+
+try_again:
+ dprintf(1, (ddt, "req: nlookup(%s) id %d type=%d\n",
+ dname, hp->id, type));
+ htp = hashtab; /* lookup relative to root */
+ if ((np = nlookup(dname, &htp, &fname, 0)) == NULL)
+ fname = "";
+ dprintf(1, (ddt, "req: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found",
+ dname, fname, cname));
+
+#ifdef LOCALDOM
+ /*
+ * if nlookup failed to find the name 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 && localdomain && !strchr(dname, '.')) {
+ (void) strcat(dname, ".");
+ (void) strcat(dname, localdomain);
+ dprintf(1, (ddt,"req: nlookup(%s) type=%d\n", dname, type));
+ htp = hashtab;
+ np = nlookup(dname, &htp, &fname, 0);
+ }
+#endif /*LOCALDOM*/
+
+#ifdef YPKLUDGE
+ /* Some braindamaged resolver software will not
+ recognize internet addresses in dot notation and
+ send out address queries for "names" such as
+ 128.93.8.1. This kludge will prevent those
+ from flooding higher level servers.
+ We simply claim to be authoritative and that
+ the domain doesn't exist.
+ Note that we could return the address but we
+ don't do that in order to encourage that broken
+ software is fixed.
+ */
+
+ if (!np && type == T_A && class == C_IN && dname) {
+ struct in_addr ina;
+
+ if (inet_aton(dname, &ina)) {
+ hp->rcode = NXDOMAIN;
+ hp->aa = 1;
+ dprintf(3, (ddt, "ypkludge: hit as '%s'\n", dname));
+ return (Finish);
+ }
+ }
+#endif /*YPKLUDGE*/
+
+ if ((!np) || (fname != dname))
+ goto fetchns;
+
+#ifdef SECURE_ZONES
+ if (np->n_data) {
+ struct zoneinfo *zp;
+
+ zp = &zones[np->n_data->d_zone];
+ if (zp->secure_nets
+ && !addr_on_netlist(from->sin_addr, zp->secure_nets)) {
+ dprintf(1, (ddt,
+ "REFUSED Unauthorized request from %s\n",
+ inet_ntoa(from->sin_addr)));
+ syslog(LOG_INFO, "Unauthorized request %s from %s",
+ dname, inet_ntoa(from->sin_addr));
+ return (Refuse);
+ }
+ }
+#endif
+ foundname++;
+ answers = *cpp;
+ count = *cpp - msg;
+
+#ifdef NCACHE
+ /* if this is a NXDOMAIN, will have only one databuf
+ * whose d_rcode field will be NXDOMAIN. So we can go home
+ * right here. -ve $ing: anant@isi.edu
+ */
+ if (np->n_data != NULL && !stale(np->n_data)) {
+ if (np->n_data->d_rcode == NXDOMAIN) {
+#ifdef RETURNSOA
+ n = finddata(np, class, T_SOA, hp, &dname,
+ buflenp, &count);
+ if (n != 0 ) {
+ if (hp->rcode == NOERROR_NODATA) {
+ /* this should not occur */
+ hp->rcode = NOERROR;
+ return (Finish);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->rcode = NXDOMAIN;
+ hp->nscount = htons((u_int16_t)count);
+ hp->aa = 1;
+ return (Finish);
+ }
+ else
+ goto fetchns;
+#else
+ hp->rcode = NXDOMAIN;
+ hp->aa = 1;
+ return (Finish);
+#endif
+ }
+ }
+
+ /* if not NXDOMAIN, the NOERROR_NODATA record might be
+ * anywhere in the chain. have to go through the grind.
+ */
+#endif /*NCACHE*/
+
+ n = finddata(np, class, type, hp, &dname, buflenp, &count);
+ if (n == 0) {
+ /* NO data available. Refuse AXFR requests, or
+ * look for better servers for other requests.
+ */
+ if (type == T_AXFR) {
+ dprintf(1, (ddt, "T_AXFR refused: no data\n"));
+ return (Refuse);
+ } else {
+ goto fetchns;
+ }
+ }
+
+#ifdef NCACHE
+ if (hp->rcode == NOERROR_NODATA) {
+ hp->rcode = NOERROR;
+ founddata = 1;
+ return (Finish);
+ }
+#endif
+
+ *cpp += n;
+ *buflenp -= n;
+ *msglenp += n;
+ hp->ancount += count;
+ if (fname != dname && type != T_CNAME && type != T_ANY) {
+ if (cname++ >= MAXCNAMES) {
+ dprintf(3, (ddt,
+ "resp: leaving, MAXCNAMES exceeded\n"));
+ hp->rcode = SERVFAIL;
+ return (Finish);
+ }
+ goto try_again;
+ }
+ founddata = 1;
+ dprintf(3, (ddt,
+ "req: foundname=%d, count=%d, founddata=%d, cname=%d\n",
+ foundname, count, founddata, cname));
+
+ if ((lp = local(from)) != NULL)
+ sort_response(answers, count, lp, *cpp);
+ if (type == T_AXFR) {
+ hp->ancount = htons(hp->ancount);
+ startxfr(qsp, np, msg, *cpp - msg, class, dname);
+ sqrm(qsp);
+ return (Return);
+ }
+
+#ifdef notdef
+ /*
+ * If we found an authoritative answer,
+ * we're done.
+ */
+ if (hp->aa)
+ return (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).
+ */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ nsp[0] = NULL;
+ count = 0;
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ if (!foundname) {
+ hp->rcode = NXDOMAIN;
+ }
+ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode));
+ 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, *cpp, *buflenp, np, nsp[0]);
+ *cpp += n;
+ *buflenp -= n;
+#ifdef ADDAUTH
+ } else if (hp->ancount) {
+ /* don't add NS records for NOERROR NODATA
+ as some severs can get confused */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ switch (findns(&np, class, nsp, &count, 1)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ break;
+ default:
+ if (np) {
+ n = add_data(np, nsp, *cpp,
+ *buflenp);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ hp->nscount =
+ htons((u_int16_t)
+ count);
+ }
+ }
+#endif /*ADDAUTH*/
+ }
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+
+ case SERVFAIL:
+ if (!founddata && !(forward_only && fwdtab)) {
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ }
+
+ /*
+ * If we successfully found the answer in the cache,
+ * or this is not a recursive query, or we are purposely
+ * never recursing, then add the nameserver references
+ * ("authority section") here and we're done.
+ */
+ if (founddata || (!hp->rd) || NoRecurse) {
+ n = add_data(np, nsp, *cpp, *buflenp);
+ if (n < 0) {
+ hp->tc = 1;
+ n = (-n);
+ }
+ *cpp += n;
+ *buflenp -= n;
+ hp->nscount = htons((u_int16_t)count);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (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) *msglenp);
+ if (omsg == (u_char *)NULL) {
+ dprintf(1, (ddt, "ns_req: malloc fail\n"));
+ syslog(LOG_ERR, "ns_req: Out Of Memory");
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+ id = hp->id;
+ hp->ancount = htons(hp->ancount);
+ omsglen = *msglenp;
+ bcopy(msg, omsg, omsglen);
+ *msglenp = res_mkquery(QUERY, dname, class, type,
+ NULL, 0, NULL, msg,
+ *msglenp + *buflenp);
+ }
+ n = ns_forw(nsp, msg, *msglenp, from, qsp, dfd, &qp, dname, np);
+ if (n != FW_OK && cname)
+ free(omsg);
+ switch (n) {
+ case FW_OK:
+ if (cname) {
+ qp->q_cname = cname;
+ qp->q_cmsg = omsg;
+ qp->q_cmsglen = omsglen;
+ qp->q_id = id;
+ }
+ break;
+ case FW_DUP:
+ break; /* Duplicate request dropped */
+ case FW_NOSERVER:
+ /*
+ ** Don't go into an infinite loop if
+ ** the admin gave root NS records in the cache
+ ** file without giving address records
+ ** for the root servers.
+ */
+ if (np) {
+ if (np->n_dname[0] == '\0') {
+ dprintf(1, (ddt,
+ "ns_req: no address for root NS\n"
+ ));
+ syslog(LOG_ERR,
+ "ns_req: no address for root server");
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+#ifdef VALIDATE
+ /*
+ * we need to kill all the NS records here as
+ * validate will fail as we are talking to the parent
+ * server
+ */
+ delete_all(np, class, T_NS);
+#endif
+ np = np->n_parent;
+ }
+ goto fetchns; /* Try again. */
+ case FW_SERVFAIL:
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Finish);
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (Return);
+}
+
+#ifdef INVQ
+static enum req_action
+req_iquery(hp, cpp, eom, buflenp, msg, from)
+ HEADER *hp;
+ u_char **cpp, *eom;
+ int *buflenp;
+ u_char *msg;
+ struct sockaddr_in *from;
+{
+ register struct invbuf *ip;
+ int dlen, alen, i, n, type, class, count;
+ char dnbuf[MAXDNAME], anbuf[PACKETSZ], *data, *fname;
+ struct namebuf *np;
+ struct qinfo *qp;
+ struct databuf *dp;
+
+ nameserIncr(from->sin_addr, nssRcvdIQ);
+
+ hp->ancount = htons(hp->ancount);
+ if ((hp->ancount != 1)
+ || hp->qdcount
+ || hp->nscount
+ || hp->arcount) {
+ dprintf(1, (ddt, "FORMERR IQuery header counts wrong\n"));
+ hp->qdcount = 0;
+ hp->ancount = 0;
+ hp->nscount = 0;
+ hp->arcount = 0;
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * Skip domain name, get class, and type.
+ */
+ if ((n = dn_skipname(*cpp, eom)) < 0) {
+ dprintf(1, (ddt, "FORMERR IQuery packet name problem\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+ *cpp += n;
+ GETSHORT(type, *cpp);
+ GETSHORT(class, *cpp);
+ *cpp += INT32SZ; /* ttl */
+ GETSHORT(dlen, *cpp);
+ *cpp += dlen;
+ if (*cpp != eom) {
+ dprintf(1, (ddt, "FORMERR IQuery message length off\n"));
+ hp->rcode = FORMERR;
+ return (Finish);
+ }
+
+ /*
+ * not all inverse queries are handled.
+ */
+ switch (type) {
+ case T_A:
+ case T_UID:
+ case T_GID:
+ break;
+ default:
+ return (Refuse);
+ }
+ dprintf(1, (ddt, "req: IQuery class %d type %d\n", class, type));
+
+ fname = (char *)msg + HFIXEDSZ;
+ bcopy(fname, anbuf, alen = (char *)*cpp - fname);
+ data = anbuf + alen - dlen;
+ *cpp = (u_char *)fname;
+ *buflenp -= HFIXEDSZ;
+ count = 0;
+ for (ip = invtab[dhash((u_char *)data, dlen)];
+ ip != NULL;
+ ip = ip->i_next) {
+ for (i = 0; i < INVBLKSZ; i++) {
+ if ((np = ip->i_dname[i]) == NULL)
+ break;
+ dprintf(5, (ddt, "dname = %d\n", np->n_dname));
+ 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));
+ dprintf(2, (ddt, "req: IQuery found %s\n",
+ dnbuf));
+ *buflenp -= QFIXEDSZ;
+ n = dn_comp(dnbuf, *cpp, *buflenp, NULL, NULL);
+ if (n < 0) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ *cpp += n;
+ PUTSHORT((u_int16_t)dp->d_type, *cpp);
+ PUTSHORT((u_int16_t)dp->d_class, *cpp);
+ *buflenp -= n;
+ count++;
+ }
+ }
+ }
+ dprintf(1, (ddt, "req: IQuery %d records\n", count));
+ hp->qdcount = htons((u_int16_t)count);
+ if (alen > *buflenp) {
+ hp->tc = 1;
+ return (Finish);
+ }
+ bcopy(anbuf, *cpp, alen);
+ *cpp += alen;
+ return (Finish);
+}
+#endif
+
+static void
+fwritemsg(rfp, msg, msglen)
+ FILE *rfp;
+ u_char *msg;
+ int msglen;
+{
+ u_char len[INT16SZ];
+
+ __putshort(msglen, len);
+ if (fwrite((char *)len, INT16SZ, 1, rfp) != 1 ||
+ fwrite((char *)msg, msglen, 1, rfp) != 1) {
+ dprintf(1, (ddt, "fwrite failed %d\n", errno));
+ }
+}
+
+/*
+ * Test a datum for validity and return non-zero if it is out of date.
+ */
+int
+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:
+#ifdef STUBS
+ case Z_STUB:
+#endif
+ /*
+ * 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 ((int32_t)(tt.tv_sec - zp->z_lastupdate)
+ > (int32_t)zp->z_expire) {
+ dprintf(1, (ddt,
+ "stale: secondary zone %s expired\n",
+ zp->z_origin));
+ if (!haveComplained(zp->z_origin, (char*)stale)) {
+ syslog(LOG_ERR,
+ "secondary zone \"%s\" expired",
+ zp->z_origin);
+ }
+ zp->z_flags &= ~Z_AUTH;
+ return (1);
+ }
+ return (0);
+
+ case Z_CACHE:
+ if (dp->d_flags & DB_F_HINT || dp->d_ttl >= tt.tv_sec)
+ return (0);
+ dprintf(3, (ddt, "stale: ttl %d %d (x%x)\n",
+ dp->d_ttl, dp->d_ttl - tt.tv_sec, dp->d_flags));
+ return (1);
+
+ default:
+ /* FALLTHROUGH */ ;
+
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Copy databuf into a resource record for replies.
+ * Return size of RR if OK, -1 if buffer is full.
+ */
+int
+make_rr(name, dp, buf, buflen, doadd)
+ char *name;
+ register struct databuf *dp;
+ u_char *buf;
+ int buflen, doadd;
+{
+ register u_char *cp;
+ u_char *cp1, *sp;
+ struct zoneinfo *zp;
+ register int32_t n;
+ register int32_t ttl;
+ u_char **edp = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
+
+ dprintf(5, (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));
+
+#ifdef NCACHE
+ if (dp->d_rcode
+#ifdef RETURNSOA
+ && dp->d_rcode != NXDOMAIN
+#endif
+ ) {
+ syslog(LOG_CRIT, "make_rr d_rcode %d", dp->d_rcode);
+#ifdef DEBUG
+ if (debug) abort();
+#endif
+ return (-1); /* XXX We should exit here */
+ }
+#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_int32_t) tt.tv_sec;
+ if ((dp->d_flags & DB_F_HINT) || (ttl < 0)) {
+ dprintf(3, (ddt,
+ "make_rr: %d=>0, x%x\n",
+ ttl, dp->d_flags)); /* XXX */
+ 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 defined(RETURNSOA) && defined(NCACHE)
+ if (dp->d_rcode == NXDOMAIN) {
+ name = (char *)dp->d_data;
+ name += strlen(name) +1;
+ name += strlen(name) +1;
+ name += 5 * INT32SZ;
+ }
+#endif
+ if ((n = dn_comp(name, buf, buflen, dnptrs, edp)) < 0)
+ return (-1);
+ cp = buf + n;
+ buflen -= n;
+ PUTSHORT((u_int16_t)dp->d_type, cp);
+ PUTSHORT((u_int16_t)dp->d_class, cp);
+ PUTLONG(ttl, cp);
+ sp = cp;
+ cp += INT16SZ;
+ switch (dp->d_type) {
+ case T_CNAME:
+ case T_MG:
+ case T_MR:
+ case T_PTR:
+ n = dn_comp((char *)dp->d_data, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)n, sp);
+ cp += n;
+ break;
+
+ case T_MB:
+ case T_NS:
+ /* Store domain name in answer */
+ n = dn_comp((char *)dp->d_data, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ PUTSHORT((u_int16_t)n, sp);
+ cp += n;
+ if (doadd)
+ addname((char*)dp->d_data, dp->d_class);
+ break;
+
+ case T_SOA:
+ case T_MINFO:
+ case T_RP:
+ cp1 = dp->d_data;
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ buflen -= dp->d_type == T_SOA ? n + 5 * INT32SZ : n;
+ cp1 += strlen((char *)cp1) + 1;
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+ if (dp->d_type == T_SOA) {
+ cp1 += strlen((char *)cp1) + 1;
+ bcopy(cp1, cp, (n = 5 * INT32SZ));
+ cp += n;
+ }
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* cp1 == our data/ cp == data of RR */
+ cp1 = dp->d_data;
+
+ /* copy preference */
+ bcopy(cp1, cp, INT16SZ);
+ cp += INT16SZ;
+ cp1 += INT16SZ;
+ buflen -= INT16SZ;
+
+ n = dn_comp((char *)cp1, cp, buflen, dnptrs, edp);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* save data length */
+ n = (u_int16_t)((cp - sp) - INT16SZ);
+ PUTSHORT((u_int16_t)n, sp);
+ if (doadd)
+ addname((char*)cp1, dp->d_class);
+ break;
+
+ default:
+ if (dp->d_size > buflen)
+ return (-1);
+ bcopy(dp->d_data, cp, dp->d_size);
+ PUTSHORT((u_int16_t)dp->d_size, sp);
+ cp += dp->d_size;
+ }
+ return (cp - buf);
+}
+
+#if defined(__STDC__) || defined(__GNUC__)
+static void
+addname(register char *name,
+ u_int16_t class)
+#else
+static void
+addname(name, class)
+ register char *name;
+ u_int16_t class;
+#endif
+{
+ 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 = (char *)malloc(strlen(name)+1);
+ strcpy(ap->a_dname,name);
+ ap->a_class = class;
+ }
+}
+
+/*
+ * Lookup addresses for names in addinfo and put into the message's
+ * additional section.
+ */
+int
+doaddinfo(hp, msg, msglen)
+ HEADER *hp;
+ u_char *msg;
+ int msglen;
+{
+ register struct namebuf *np;
+ register struct databuf *dp;
+ register struct addinfo *ap;
+ register u_char *cp;
+ struct hashbuf *htp;
+ char *fname;
+ int n, count;
+
+ dprintf(3, (ddt, "doaddinfo() addcount = %d\n", addcount));
+
+ if (hp->tc) {
+ dprintf(4, (ddt, "doaddinfo(): tc already set, bailing\n"));
+ return (0);
+ }
+
+ count = 0;
+ cp = msg;
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ int foundstale = 0,
+ foundany = 0,
+ save_count = count,
+ save_msglen = msglen;
+ u_char *save_cp = cp;
+
+ dprintf(3, (ddt, "do additional '%s'\n", ap->a_dname));
+ htp = hashtab; /* because "nlookup" stomps on arg. */
+ np = nlookup(ap->a_dname, &htp, &fname, 0);
+ if (np == NULL || fname != ap->a_dname)
+ goto next_rr;
+ dprintf(3, (ddt, "found it\n"));
+ /* look for the data */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if ( (!match(dp, (int)ap->a_class, T_A))
+ && (!match(dp, C_IN, T_A))
+ ) {
+ continue;
+ }
+ foundany++;
+ if (stale(dp)) {
+ foundstale++;
+ dprintf(1, (ddt,
+ "doaddinfo: stale entry '%s'%s\n",
+ np->n_dname,
+ (dp->d_flags&DB_F_HINT)
+ ? " hint"
+ : ""
+ ));
+ continue;
+ }
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ /*
+ * Should be smart and eliminate duplicate
+ * data here. XXX
+ */
+ if ((n = make_rr(ap->a_dname, dp, cp, msglen, 0)) < 0){
+ /* truncation in the additional-data section
+ * is not all that serious. we do not set TC,
+ * since the answer and authority sections are
+ * OK; however, since we're not setting TC we
+ * have to make sure that none of the RR's for
+ * this name go out (!TC implies that all
+ * {name,type} appearances are complete -- and
+ * since we only do A RR's here, the name is
+ * the key). vixie, 23apr93
+ */
+ cp = save_cp;
+ msglen = save_msglen;
+ count = save_count;
+ break;
+ }
+ dprintf(5, (ddt,
+ "addinfo: adding address data n = %d\n",
+ n));
+ cp += n;
+ msglen -= n;
+ count++;
+ }
+next_rr: if (foundstale) {
+ /* Cache invalidate the address RR's */
+ delete_all(np, (int)ap->a_class, T_A);
+ }
+ if (foundstale || !foundany) {
+ /* ask a real server for this info */
+ (void) sysquery(ap->a_dname, (int)ap->a_class, T_A,
+ NULL, 0);
+ }
+ free(ap->a_dname);
+ }
+ hp->arcount = htons((u_int16_t)count);
+ return (cp - msg);
+}
+
+int
+doaddauth(hp, cp, buflen, np, dp)
+ register HEADER *hp;
+ u_char *cp;
+ int buflen;
+ struct namebuf *np;
+ struct databuf *dp;
+{
+ char dnbuf[MAXDNAME];
+ int n;
+
+ getname(np, dnbuf, sizeof(dnbuf));
+ if (stale(dp)) {
+ dprintf(1, (ddt,
+ "doaddauth: can't add stale '%s' (%d)\n",
+ dnbuf, buflen));
+ return (0);
+ }
+ n = make_rr(dnbuf, dp, cp, buflen, 1);
+ if (n <= 0) {
+ dprintf(1, (ddt,
+ "doaddauth: can't add oversize '%s' (%d) (n=%d)\n",
+ dnbuf, buflen, n));
+ if (n < 0) {
+ hp->tc = 1;
+ }
+ return (0);
+ }
+ hp->nscount = htons((u_int16_t)1);
+ return (n);
+}
+
+/*
+ * Do a zone transfer (or a recursive part of a zone transfer).
+ * SOA record already sent.
+ *
+ * top always refers to the domain at the top of the zone being transferred.
+ * np refers to a domain inside the zone being transferred,
+ * which will be equal to top if this is the first call,
+ * or will be a subdomain below top if this is a recursive call,
+ * rfp is a stdio file to which output is sent.
+ */
+static void
+doaxfr(np, rfp, top, class)
+ register struct namebuf *np;
+ FILE *rfp;
+ struct namebuf *top;
+ int class; /* Class to transfer */
+{
+ register struct databuf *dp;
+ register int n;
+ struct hashbuf *htp;
+ struct databuf *gdp; /* glue databuf */
+ struct namebuf *gnp; /* glue namebuf */
+ struct namebuf *tnp; /* top namebuf */
+ struct databuf *tdp; /* top databuf */
+ struct namebuf **npp, **nppend;
+ u_char msg[PACKETSZ];
+ u_char *cp;
+ char *fname;
+ char dname[MAXDNAME];
+ HEADER *hp = (HEADER *) msg;
+ int fndns;
+
+ if (np == top)
+ dprintf(1, (ddt, "doaxfr()\n"));
+ 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 = (u_char *) (msg + HFIXEDSZ);
+ getname(np, dname, sizeof(dname));
+
+ /* first do the NS records (del@harris) */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+#ifdef GEN_AXFR
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+#endif
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (dp->d_type == T_NS) {
+ fndns = 1;
+ n = make_rr(dname, dp, cp, sizeof(msg)-HFIXEDSZ, 0);
+ if (n < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+#ifdef NO_GLUE
+ if ((np != top) || (top->n_dname[0] == '\0')) {
+#endif /*NO_GLUE*/
+ /* Glue the sub domains together by sending
+ * the address records for the sub domain
+ * name servers along if necessary.
+ * Glue is necessary if the server is in any zone
+ * delegated from the current (top) zone. Such
+ * a delegated zone might or might not be that
+ * referred to by the NS record now being handled.
+ */
+ htp = hashtab;
+ cp = (u_char *) (msg + HFIXEDSZ);
+ gnp = nlookup((char *)dp->d_data, &htp, &fname, 0);
+ if (gnp == NULL || fname != (char *)dp->d_data)
+ continue;
+#ifdef NO_GLUE
+ for (tnp = gnp; tnp != NULL; tnp = tnp->n_parent)
+ if ( tnp == top )
+ break;
+ if ( (tnp == NULL) && (top->n_dname[0] != '\0') )
+ continue; /* name server is not below top domain */
+ for (tnp = gnp; tnp != top; tnp = tnp->n_parent) {
+ for (tdp = tnp->n_data;
+ tdp != NULL;
+ tdp = tdp->d_next) {
+#ifdef GEN_AXFR
+ if (tdp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ if (tdp->d_type == T_NS)
+ break;
+ }
+ if (tdp != NULL)
+ break; /* found a zone cut */
+ }
+ if (tnp == top)
+ continue; /* name server is not in a delegated zone */
+ /* now we know glue records are needed. send them. */
+#endif /*NO_GLUE*/
+ for (gdp=gnp->n_data; gdp != NULL; gdp=gdp->d_next) {
+#ifdef GEN_AXFR
+ if (gdp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ if (gdp->d_type != T_A || stale(gdp))
+ continue;
+#ifdef NCACHE
+ if (gdp->d_rcode)
+ continue;
+#endif
+ n = make_rr(fname, gdp, cp, sizeof(msg)-HFIXEDSZ, 0);
+ if (n < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+ }
+#ifdef NO_GLUE
+ }
+#endif /*NO_GLUE*/
+ }
+ }
+ /* no need to send anything else if a delegation appeared */
+ if ((np != top) && fndns)
+ return;
+
+ /* do the rest of the data records */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+#ifdef GEN_AXFR
+ if (dp->d_class != class && class != C_ANY)
+ continue;
+#endif
+ /*
+ * Skip the top SOA record (marks end of data);
+ * don't send SOA for subdomains, as we're not sending them;
+ * skip the NS records because we did them first.
+ */
+ if (dp->d_type == T_SOA || dp->d_type == T_NS)
+ continue;
+ if (dp->d_zone == 0 || stale(dp))
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if ((n = make_rr(dname, dp, cp, sizeof(msg)-HFIXEDSZ, 0)) < 0)
+ continue;
+ fwritemsg(rfp, msg, n + HFIXEDSZ);
+ }
+
+ /* Finally do non-delegated subdomains. Delegated subdomains
+ * have already been handled.
+ */
+ /*
+ * We find the subdomains by looking in the hash table for this
+ * domain, but the root domain needs special treatment, because
+ * of the following wart in the database design:
+ *
+ * The top level hash table (pointed to by the global `hashtab'
+ * variable) contains pointers to the namebuf's for the root as
+ * well as for the top-level domains below the root, in contrast
+ * to the usual situation where a hash table contains entries
+ * for domains at the same level. The n_hash member of the
+ * namebuf for the root domain is NULL instead of pointing to a
+ * hashbuf for the top-level domains. The n_parent members of
+ * the namebufs for the top-level domains are NULL instead of
+ * pointing to the namebuf for the root.
+ *
+ * We work around the wart as follows:
+ *
+ * If we are not dealing with the root zone then we just set
+ * htp = np->n_hash, pointing to the hash table for the current
+ * domain, and we walk through the hash table as usual,
+ * processing the namebufs for all the subdomains.
+ *
+ * If we are dealing with the root zone, then we set
+ * htp = hashtab, pointing to the global hash table (because
+ * there is no hash table associated with the root domain's
+ * namebuf. While we walk this hash table, we take care not to
+ * recursively process the entry for the root namebuf.
+ *
+ * (apb@und nov1990)
+ */
+ htp = ((dname[0] == '\0') ? hashtab : np->n_hash);
+ if (htp == NULL) {
+ return; /* no subdomains */
+ }
+ npp = htp->h_tab;
+ nppend = npp + htp->h_size;
+ while (npp < nppend) {
+ for (np = *npp++; np != NULL; np = np->n_next) {
+ if (np->n_dname[0] != '\0') { /* don't redo root domain */
+ doaxfr(np, rfp, top, class);
+ }
+ }
+ }
+ if (np == top)
+ dprintf(1, (ddt, "exit doaxfr()\n"));
+}
+
+#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.
+ */
+static int
+InitDynUpdate(hp, msg, msglen, startcp, from, qsp, dfd)
+ register HEADER *hp;
+ char *msg;
+ int msglen;
+ u_char *startcp;
+ struct sockaddr_in *from;
+ struct qstream *qsp;
+ int dfd;
+{
+ struct databuf *nsp[NSMAX];
+ 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;
+ u_int16_t class, type;
+ int n, size, zonenum;
+ char ZoneName[MAXDNAME], *znp;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ if ((n = dn_expand(msg, msg + msglen, cp, dnbuf, sizeof(dnbuf))) < 0) {
+ dprintf(1, (ddt,"FORMERR InitDynUpdate expand name failed\n"));
+ hp->rcode = FORMERR;
+ return (FORMERR);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ if (type == T_SOA) { /* T_SOA updates not allowed */
+ hp->rcode = REFUSED;
+ dprintf(1, (ddt, "InitDynUpdate: REFUSED - SOA update\n"));
+ return (REFUSED);
+ }
+ GETSHORT(class, cp);
+ cp += INT32SZ;
+ 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;
+ dprintf(1, (ddt,
+ "InitDynUpdate: REFUSED - non-{primary,secondary} update\n"));
+ return (REFUSED);
+ }
+ if (!(zp->z_flags & Z_DYNAMIC)) {
+ hp->rcode = REFUSED;
+ dprintf(1, (ddt,
+ "InitDynUpdate: REFUSED - dynamic flag not set for zone\n"));
+ 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)) {
+ dprintf(1, (ddt, "InitDynUpdate: lookup failed on zone (%s)\n",
+ ZoneName));
+ 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;
+#ifdef DATUMREFCNT
+ dp->d_rcnt++;
+#endif
+ } else
+ break;
+ }
+ dp = dp->d_next;
+ }
+ *nspp = NULL; /* Delimiter */
+ if (ns_forw(nsp, msg, msglen, from, qsp, dfd, NULL, dnbuf, np)
+ <
+ 0) {
+ hp->rcode = SERVFAIL;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (SERVFAIL);
+ }
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (FORWARDED);
+
+ case Z_PRIMARY:
+ zp->z_serial++;
+ /* 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) {
+ dprintf(1, (ddt,
+ "InitDynUpdate: Couldn't find SOA record for '%s'\n",
+ ZoneName));
+ syslog(LOG_ERR,
+ "InitDynUpdate: Couldn't find SOA record for '%s'\n"
+,
+ ZoneName);
+ hp->rcode = NXDOMAIN;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ 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;
+ newdp->d_cred = DB_C_AUTH; /* XXX - it may not be so */
+ newdp->d_clev = db_getclev(zp->z_origin);
+ cp = (u_char *)newdp->d_data;
+ cp += strlen(cp) + 1; /* skip origin string */
+ cp += strlen(cp) + 1; /* skip in-charge string */
+ putlong((u_int32_t)(zp->z_serial), cp);
+ dprintf(4, (ddt, "after stuffing data into newdp:\n"));
+#ifdef DEBUG
+ if (debug >= 4)
+ printSOAdata(newdp);
+#endif
+
+ if ((n = db_update(ZoneName, olddp, newdp, DB_DELETE,
+ hashtab)) != NOERROR) { /* XXX */
+ dprintf(1, (ddt,
+ "InitDynUpdate: SOA update failed\n"));
+ hp->rcode = NOCHANGE;
+ free((char*) dp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (NOCHANGE);
+ }
+
+ /* Now update the RR itself */
+ /* XXX - DB_C_AUTH may be wrong */
+ if (doupdate(msg, msglen, msg + HFIXEDSZ, zonenum,
+ (struct databuf *)0, DB_NODATA, DB_C_AUTH) < 0) {
+ dprintf(1, (ddt, "InitDynUpdate: doupdate failed\n"));
+ /* doupdate fills in rcode */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (hp->rcode);
+ }
+ zp->z_flags |= Z_CHANGED;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (NOERROR);
+ }
+}
+
+#ifdef DEBUG
+/*
+ * Print the contents of the data in databuf pointed to by dp for an SOA record
+ */
+static void
+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
+#endif
+
+static void
+startxfr(qsp, np, soa, soalen, class, dname)
+ struct qstream *qsp;
+ struct namebuf *np;
+ u_char *soa;
+ int soalen;
+ int class;
+ const char *dname;
+{
+ FILE *rfp;
+ int fdstat;
+ pid_t pid;
+
+ dprintf(5, (ddt, "startxfr()\n"));
+
+ /*
+ * child does the work while
+ * the parent continues
+ */
+ switch (pid = fork()) {
+ case -1:
+ syslog(LOG_ERR, "startxfr(%s -> [%s]) failing; fork: %m",
+ dname, inet_ntoa(qsp->s_from.sin_addr));
+ return;
+ case 0:
+ /* child */
+ break;
+ default:
+ /* parent */
+ syslog(LOG_DEBUG, "zone transfer of \"%s\" to [%s] (pid %lu)",
+ dname, inet_ntoa(qsp->s_from.sin_addr), pid);
+ return;
+ }
+
+ /*
+ * Child.
+ *
+ * XXX: this should be a vfork/exec since on non-copy-on-write
+ * systems with huge nameserver images, this is very expensive.
+ */
+ close(vs);
+ sqflush(/*allbut*/ qsp);
+ dqflush((time_t)0);
+
+#ifdef RENICE
+ nice(-40); nice(20); nice(0); /* back to "normal" */
+#endif
+ dprintf(5, (ddt, "startxfr: child pid %lu\n", (u_long)pid));
+
+ if (!(rfp = fdopen(qsp->s_rfd, "w"))) {
+ syslog(LOG_ERR, "fdopen: %m");
+ _exit(1);
+ }
+ ns_setproctitle("zone XFR to", qsp->s_rfd);
+ if (-1 == (fdstat = fcntl(qsp->s_rfd, F_GETFL, 0))) {
+ syslog(LOG_ERR, "fcntl(F_GETFL): %m");
+ _exit(1);
+ }
+ (void) fcntl(qsp->s_rfd, F_SETFL, fdstat & ~PORT_NONBLOCK);
+ fwritemsg(rfp, soa, soalen);
+ doaxfr(np, rfp, np, class);
+ fwritemsg(rfp, soa, soalen);
+ (void) fflush(rfp);
+ _exit(0);
+}
+
+free_addinfo() {
+ struct addinfo *ap;
+
+ for (ap = addinfo; --addcount >= 0; ap++) {
+ free(ap->a_dname);
+ }
+ addcount = 0;
+}
+
+#ifdef DATUMREFCNT
+free_nsp(nsp)
+struct databuf **nsp;
+{
+ while (*nsp) {
+ if (--((*nsp)->d_rcnt)) {
+ dprintf(3, (ddt, "free_nsp: %s rcnt %d\n",
+ (*nsp)->d_data, (*nsp)->d_rcnt));
+ } else {
+ dprintf(3, (ddt, "free_nsp: %s rcnt %d delayed\n",
+ (*nsp)->d_data, (*nsp)->d_rcnt));
+ free(*nsp); /* delayed free */
+ }
+ *nsp++ = NULL;
+ }
+}
+#endif
diff --git a/usr.sbin/named/ns_resp.c b/usr.sbin/named/ns_resp.c
new file mode 100644
index 0000000..f8086e3
--- /dev/null
+++ b/usr.sbin/named/ns_resp.c
@@ -0,0 +1,2190 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_resp.c 4.65 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_resp.c,v 4.9.1.24 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1988, 1990
+ * -
+ * Copyright (c) 1986, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+static void check_root __P((void)),
+ check_ns __P((void));
+
+static u_int8_t norootlogged[MAXCLASS]; /* XXX- should be a bitmap */
+
+static char skipnameFailedAnswer[] = "skipname failed in answer",
+ skipnameFailedQuery[] = "skipname failed in query",
+ outofDataQuery[] = "ran out of data in query",
+ outofDataAnswer[] = "ran out of data in answer",
+#ifdef LAME_DELEGATION
+ expandFailedQuery[] = "dn_expand failed in query",
+ expandFailedAuth[] = "dn_expand failed in authority",
+ outofDataAuth[] = "ran out of data in authority",
+#endif /* LAME_DELEGATION */
+ dlenOverrunAnswer[] = "dlen overrun in answer",
+ dlenUnderrunAnswer[] = "dlen underrun in answer",
+ outofDataFinal[] = "out of data in final pass",
+ outofDataAFinal[] = "out of data after final pass";
+
+void
+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;
+#ifdef VALIDATE
+ register u_char *tempcp;
+ struct sockaddr_in *server = &from_addr;
+ int *validatelist;
+ int lesscount;
+#endif
+ struct sockaddr_in *nsa;
+ struct databuf *nsp[NSMAX], **nspp;
+ int i, c, n, ancount, aucount, nscount, arcount;
+ int old_ancount;
+ 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;
+ char *formerrmsg = "brain damage";
+ u_char newmsg[BUFSIZ];
+ u_char **dpp, *tp;
+ time_t rtrip;
+ struct hashbuf *htp;
+ struct namebuf *np;
+ struct netinfo *lp;
+ struct fwdinfo *fwd;
+
+ nameserIncr(from_addr.sin_addr, nssRcvdR);
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ hp = (HEADER *) msg;
+ if ((qp = qfindid(hp->id)) == NULL ) {
+ dprintf(1, (ddt, "DUP? dropped (id %d)\n", ntohs(hp->id)));
+ nameserIncr(from_addr.sin_addr, nssRcvdDupR);
+ return;
+ }
+
+ dprintf(2, (ddt, "Response (%s %s %s) nsid=%d id=%d\n",
+ (qp->q_flags & Q_SYSTEM) ?"SYSTEM" :"USER",
+ (qp->q_flags & Q_PRIMING) ?"PRIMING" :"NORMAL",
+ (qp->q_flags & Q_ZSERIAL) ?"ZSERIAL" :"-",
+ ntohs(qp->q_nsid), ntohs(qp->q_id)));
+
+ /*
+ * 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.
+ */
+ if ((hp->rcode != NOERROR && hp->rcode != NXDOMAIN)
+#ifndef NCACHE
+ || (hp->rcode == NXDOMAIN && !hp->aa) /* must accept this one if
+ * we allow negative caching
+ */
+#endif /*NCACHE*/
+ || hp->opcode != QUERY) {
+ dprintf(2, (ddt, "resp: error (ret %d, op %d), dropped\n",
+ hp->rcode, hp->opcode));
+ switch (hp->rcode) {
+ case SERVFAIL:
+ nameserIncr(from_addr.sin_addr, nssRcvdFail);
+ break;
+ case FORMERR:
+ nameserIncr(from_addr.sin_addr, nssRcvdFErr);
+ break;
+ default:
+ nameserIncr(from_addr.sin_addr, nssRcvdErr);
+ break;
+ }
+ return;
+ }
+#ifdef LAME_DELEGATION
+ /*
+ * Non-authoritative, no answer, no error
+ */
+ if (hp->rcode == NOERROR && !hp->aa && ntohs(hp->ancount) == 0 &&
+ ntohs(hp->nscount) > 0) {
+
+#ifdef LAME_LOGGING
+ char qname[MAXDNAME];
+#endif /* LAME_LOGGING */
+
+#ifdef DEBUG
+ if (debug > 0)
+ fp_query(msg, ddt);
+#endif
+
+ cp = msg + HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ if (hp->qdcount) {
+#ifdef LAME_LOGGING
+ n = dn_expand(msg, msg + msglen, cp, qname,
+ sizeof(qname));
+ if (n <= 0) {
+ formerrmsg = expandFailedQuery;
+ goto formerr;
+ }
+#else /* LAME_LOGGING */
+ n = dn_skipname(cp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedQuery;
+ goto formerr;
+ }
+#endif /* LAME_LOGGING */
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataQuery;
+ goto formerr;
+ }
+#ifdef LAME_LOGGING
+ } else {
+ strcpy(qname, "[No query name!]");
+#endif /* LAME_LOGGING */
+ }
+ n = dn_expand(msg, msg + msglen, cp, name, sizeof name);
+ if (n < 0) {
+ formerrmsg = expandFailedAuth;
+ goto formerr;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataAuth;
+ goto formerr;
+ }
+
+ /*
+ * If the answer delegates us either to the same level in
+ * the hierarchy or closer to the root, we consider this
+ * server lame.
+ */
+
+ if (type == T_NS && samedomain(qp->q_domain, name)) {
+ nameserIncr(from_addr.sin_addr, nssRcvdLDel);
+#ifdef LAME_LOGGING
+ if (!haveComplained((char*)dhash((u_char*)name,
+ strlen(name)),
+ (char*)dhash((u_char*)qp->q_domain,
+ strlen(qp->q_domain)
+ )
+ )
+ ) {
+ syslog(LAME_LOGGING,
+"Lame delegation to '%s' from [%s] (server for '%s'?) on query on name '%s'\n",
+ name, inet_ntoa(from_addr.sin_addr),
+ qp->q_domain, qname);
+ }
+#endif /* LAME_LOGGING */
+ return;
+ }
+ }
+#endif /* LAME_DELEGATION */
+
+
+#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
+ */
+ /* XXX - DB_C_AUTH may be wrong */
+ (void) doupdate(qp->q_msg, qp->q_msglen, qp->q_msg + HFIXEDSZ,
+ 0, (struct databuf *)0, 0, DB_C_AUTH);
+ dprintf(3, (ddt, "resp: leaving, UPDATE*\n"));
+ /* 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 (fwd->fwdaddr.sin_addr.s_addr ==
+ from_addr.sin_addr.s_addr) {
+ /* XXX - should put this in STATS somewhere */
+ break;
+ }
+ }
+ /* XXX: note bad ambiguity here. if one of our forwarders is also
+ * a delegated server for some domain, then we will not update
+ * the RTT information on any replies we get from those servers.
+ */
+ /*
+ * 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 (qs->ns_addr.sin_addr.s_addr ==
+ from_addr.sin_addr.s_addr)
+ break;
+ if (n >= qp->q_naddr) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "unexpected source")) {
+ syslog(LOG_NOTICE,
+ "Response from unexpected source [%s].%d",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port));
+ }
+ /*
+ * 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 ((qs->ns != NULL) && (stp->tv_sec == 0)) {
+ ns = qs->ns;
+ while (qs > qp->q_addr &&
+ (qs->stime.tv_sec == 0 || qs->ns != ns))
+ qs--;
+ *stp = qs->stime;
+ /* XXX - sometimes stp still ends up pointing to
+ * a zero timeval, in spite of the above attempt.
+ * Why? What should we do about it?
+ */
+ dprintf(1, (ddt,
+ "Response from unused address %s, assuming %s\n",
+ inet_ntoa(from_addr.sin_addr),
+ inet_ntoa(qs->ns_addr.sin_addr)));
+ /* XXX - catch aliases here */
+ }
+
+ /* compute query round trip time */
+ /* XXX - avoid integer overflow, which is quite likely if stp
+ * points to a zero timeval (see above).
+ * rtrip is of type time_t, which we assume is at least
+ * as big as an int.
+ */
+ if ((tt.tv_sec - stp->tv_sec) > (INT_MAX-999)/1000) {
+ rtrip = INT_MAX;
+ } else {
+ rtrip = ((tt.tv_sec - stp->tv_sec) * 1000 +
+ (tt.tv_usec - stp->tv_usec) / 1000);
+ }
+
+ dprintf(3, (ddt, "stime %d/%d now %d/%d rtt %d\n",
+ stp->tv_sec, stp->tv_usec,
+ tt.tv_sec, tt.tv_usec, rtrip));
+
+ /* 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 && (ns->d_type==T_A) && (ns->d_class==qs->ns->d_class)){
+ if (ns->d_nstime == 0)
+ ns->d_nstime = (u_int32_t)rtrip;
+ else
+ ns->d_nstime = (u_int32_t)
+ (ns->d_nstime * ALPHA
+ +
+ (1-ALPHA) * (u_int32_t)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 (ns && qs->ns && (qp->q_nusedns < NSMAX)) {
+ qp->q_usedns[qp->q_nusedns++] = qs->ns;
+ dprintf(2, (ddt, "NS #%d addr [%s] used, rtt %d\n",
+ n, inet_ntoa(qs->ns_addr.sin_addr),
+ ns->d_nstime));
+ }
+
+ /*
+ * 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) || (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 = (u_int32_t)(rtrip * BETA);
+ else
+ ns2->d_nstime = (u_int32_t)(
+ ns2->d_nstime * BETA + (1-ALPHA) * rtrip
+ );
+ if (ns2->d_nstime > 1000000)
+ ns2->d_nstime = 1000000;
+ } else
+ ns2->d_nstime = (u_int32_t)(ns2->d_nstime * GAMMA);
+ dprintf(2, (ddt, "NS #%d [%s] rtt now %d\n", n,
+ inet_ntoa(qs->ns_addr.sin_addr),
+ ns2->d_nstime));
+ }
+ }
+
+ /*************************************************************/
+
+ /*
+ * Skip query section
+ */
+ free_addinfo(); /* sets addcount to zero */
+ cp = msg + HFIXEDSZ;
+ dpp = dnptrs;
+ *dpp++ = msg;
+ if ((*cp & INDIR_MASK) == 0)
+ *dpp++ = cp;
+ *dpp = NULL;
+ type = class = 0;
+ if (hp->qdcount) {
+ n = dn_skipname(cp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedQuery;
+ goto formerr;
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ if (cp - msg > msglen) {
+ formerrmsg = outofDataQuery;
+ 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;
+ dprintf(3, (ddt, "resp: ancount %d, aucount %d, arcount %d\n",
+ ancount, aucount, arcount));
+
+ /*
+ * 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) {
+ formerrmsg = outofDataAnswer;
+ goto formerr;
+ }
+ n = dn_skipname(tp, msg + msglen);
+ if (n <= 0) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* name */
+ GETSHORT(i, tp); /* type */
+ tp += INT16SZ; /* class */
+ tp += INT32SZ; /* ttl */
+ GETSHORT(count, tp); /* dlen */
+ if (tp - msg > msglen - count) {
+ formerrmsg = dlenOverrunAnswer;
+ goto formerr;
+ }
+ tp += count;
+ if (ancount && i == T_CNAME) {
+ cname++;
+ dprintf(1,
+ (ddt,
+ "CNAME - needs more processing\n"
+ )
+ );
+ 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;
+ }
+
+ if (qp->q_flags & Q_ZSERIAL) {
+ if ((hp->aa)
+ && (ancount != 0)
+ && (hp->rcode == NOERROR)
+ && (type == T_SOA)
+ && ((class == C_IN) || (class == C_HS))
+ ) { /* XXX - should check name, too */
+ int n;
+ u_int16_t dlen;
+ u_int32_t serial;
+ u_char *tp = cp;
+
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n /* name */
+ + INT16SZ /* type */
+ + INT16SZ /* class */
+ + INT32SZ; /* ttl */
+ GETSHORT(dlen, tp); /* dlen */
+
+ if (dlen < (5 * INT32SZ)) {
+ formerrmsg = dlenUnderrunAnswer;
+ goto formerr;
+ }
+
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* mname */
+ if (0 >= (n = dn_skipname(tp, msg + msglen))) {
+ formerrmsg = skipnameFailedAnswer;
+ goto formerr;
+ }
+ tp += n; /* rname */
+ GETLONG(serial, tp);
+
+ qserial_answer(qp, serial);
+ }
+ qremove(qp);
+ return;
+ }
+
+ /*
+ * Add the info received in the response to the data base.
+ */
+ c = ancount + aucount + arcount;
+#ifdef NCACHE
+ /* -ve $ing non-existence of record, must handle non-authoritative
+ * NOERRORs with c == 0.
+ */
+ if (!hp->aa && hp->rcode == NOERROR && c == 0) {
+ goto return_msg;
+ } /*should ideally validate message before returning it*/
+#endif /*NCACHE*/
+#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_flags & Q_SYSTEM)) {
+ dprintf(4, (ddt, "resp: leaving, no CNAME\n"));
+
+ /* 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_flags & Q_SYSTEM)
+ dbflags = DB_NOTAUTH | DB_NODATA;
+ else
+ dbflags = DB_NOTAUTH | DB_NODATA | DB_NOHINTS;
+ count = c;
+ if (hp->tc) {
+ count -= arcount; /* truncation had to affect this */
+ if (!arcount) {
+ count -= aucount; /* guess it got this too */
+ }
+ if (!(arcount || aucount)) {
+ count -= ancount; /* things are pretty grim */
+ }
+ /* XXX - should retry this query with TCP */
+ }
+#ifdef VALIDATE
+ tempcp = cp;
+ validatelist = (int *)malloc(count * sizeof(int));
+ lesscount = 0; /*initialize*/
+ old_ancount = ancount;
+ for (i = 0; i < count; i++) {
+ int VCode;
+ if (tempcp >= msg + msglen) {
+ free((char *)validatelist);
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ if ((n = dovalidate(msg, msglen, tempcp, 0,
+ dbflags, server, &VCode)) < 0) {
+ dprintf(1, (ddt,
+ "resp: leaving, dovalidate failed\n"));
+ free((char *)validatelist);
+
+ /* return code filled in by dovalidate */
+ goto return_msg;
+ }
+ validatelist[i] = VCode;
+ if (VCode == INVALID) lesscount++;
+ tempcp += n;
+ }
+
+ /* need to delete INVALID records from the message
+ * and change fields appropriately
+ */
+ n = update_msg(msg, &msglen, validatelist, count);
+ free((char *)validatelist);
+ if (n < 0)
+ goto formerr;
+ count -= lesscount;
+
+ if (old_ancount && !hp->ancount) {
+ /* We lost all the answers */
+ dprintf(1, (ddt, "validate count -> 0"));
+ return;
+ }
+ ancount = ntohs(hp->ancount);
+#endif
+
+ for (i = 0; i < count; i++) {
+ struct databuf *ns3;
+ u_char cred;
+
+ if (cp >= msg + msglen) {
+ formerrmsg = outofDataFinal;
+ goto formerr;
+ }
+ if (i < ancount) {
+ cred = hp->aa ? DB_C_AUTH : DB_C_ANSWER;
+ } else {
+ cred = DB_C_ADDITIONAL;
+ }
+ ns3 = 0;
+ n = doupdate(msg, msglen, cp, 0, &ns3, dbflags, cred);
+ if (n < 0) {
+ dprintf(1, (ddt, "resp: leaving, doupdate failed\n"));
+
+ /* 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;
+#ifdef DATUMREFCNT
+ ns3->d_rcnt++;
+ *nspp = NULL;
+#endif
+ }
+ cp += n;
+ }
+
+ if ((qp->q_flags & Q_SYSTEM) && ancount) {
+ if (qp->q_flags & Q_PRIMING)
+ check_root();
+ dprintf(3, (ddt, "resp: leaving, SYSQUERY ancount %d\n",
+ ancount));
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+ }
+
+ if (cp > msg + msglen) {
+ formerrmsg = outofDataAFinal;
+ 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)) {
+ dprintf(3, (ddt, "resp: got as much answer as there is\n"));
+ goto return_msg;
+ }
+
+ /*
+ * We might want to cache this negative answer.
+ */
+ if (!ancount &&
+ (!nscount || hp->rcode == NXDOMAIN) &&
+ (hp->aa || fwd || class == C_ANY)) {
+ /* we have an authoritative NO */
+ dprintf(3, (ddt, "resp: leaving auth NO\n"));
+ if (qp->q_cmsglen) {
+ msg = qp->q_cmsg;
+ msglen = qp->q_cmsglen;
+ hp = (HEADER *)msg;
+ }
+#ifdef NCACHE
+ /* answer was NO */
+ if (hp->aa &&
+ ((hp->rcode == NXDOMAIN) || (hp->rcode == NOERROR))) {
+ cache_n_resp(msg, msglen);
+ }
+#endif /*NCACHE*/
+ 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) {
+ dprintf(1, (ddt, "Cname second pass\n"));
+ 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 + HFIXEDSZ;
+ if (cname)
+ cp += dn_skipname(cp, newmsg + newmsglen) + QFIXEDSZ;
+ n = dn_expand(newmsg, newmsg + newmsglen, cp, dname, sizeof name);
+ if (n < 0) {
+ dprintf(1, (ddt, "dn_expand failed\n"));
+ goto servfail;
+ }
+ if (!cname)
+ cp += n + QFIXEDSZ;
+ buflen = sizeof(newmsg) - (cp - newmsg);
+
+try_again:
+ dprintf(1, (ddt, "resp: nlookup(%s) type=%d\n", dname, type));
+ fname = "";
+ htp = hashtab; /* lookup relative to root */
+ np = nlookup(dname, &htp, &fname, 0);
+ dprintf(1, (ddt, "resp: %s '%s' as '%s' (cname=%d)\n",
+ np == NULL ? "missed" : "found", dname, fname, cname));
+ 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;
+
+ dprintf(3, (ddt,
+ "resp: foundname=%d, count=%d, founddata=%d, cname=%d\n",
+ foundname, count, founddata, cname));
+
+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).
+ */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN: /* shouldn't happen */
+ dprintf(3, (ddt, "req: leaving (%s, rcode %d)\n",
+ dname, hp->rcode));
+ if (!foundname)
+ hp->rcode = NXDOMAIN;
+ 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 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_int16_t)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) {
+ dprintf(1,
+ (ddt,
+ "resp: MAXQUERIES exceeded (%s, class %d, type %d)\n",
+ dname, class, type
+ )
+ );
+ syslog(LOG_NOTICE,
+ "MAXQUERIES exceeded, possible data loop in resolving (%s)",
+ dname);
+ goto servfail;
+ }
+
+ /* Reset the query control structure */
+#ifdef DATUMREFCNT
+ for (i = 0 ; i < qp->q_naddr ; i++) {
+ if ((--(qp->q_addr[i].ns->d_rcnt))) {
+ dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d\n",
+ qp->q_addr[i].ns->d_data,
+ qp->q_addr[i].ns->d_rcnt));
+ } else {
+ dprintf(1 ,(ddt, "ns_resp: ns %s rcnt %d delayed\n",
+ qp->q_addr[i].ns->d_data,
+ qp->q_addr[i].ns->d_rcnt));
+ free((char*)qp->q_addr[i].ns);
+ }
+ if ((--(qp->q_addr[i].nsdata->d_rcnt))) {
+ dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d\n",
+ *(int32_t *)(qp->q_addr[i].nsdata->d_data),
+ qp->q_addr[i].nsdata->d_rcnt));
+ } else {
+ dprintf(1 ,(ddt, "ns_resp: nsdata %08.8X rcnt %d delayed\n",
+ *(int32_t *)(qp->q_addr[i].nsdata->d_data),
+ qp->q_addr[i].nsdata->d_rcnt));
+ free((char*)qp->q_addr[i].nsdata);
+ }
+ }
+#endif
+ qp->q_naddr = 0;
+ qp->q_curaddr = 0;
+ qp->q_fwd = fwdtab;
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof(qp->q_domain));
+#endif /* LAME_DELEGATION */
+ if ((n = nslookup(nsp, qp, dname, "ns_resp")) <= 0) {
+ if (n < 0) {
+ dprintf(3, (ddt, "resp: nslookup reports danger\n"));
+ } else {
+ dprintf(3, (ddt, "resp: no addrs found for NS's\n"));
+ }
+ if (cname) /* a remote CNAME that does not have data */
+ goto return_newmsg;
+ 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) {
+ dprintf(3, (ddt,
+ "resp: leaving, MAXCNAMES exceeded\n"));
+ goto servfail;
+ }
+ dprintf(1, (ddt, "q_cname = %d\n",qp->q_cname));
+ dprintf(3, (ddt,
+ "resp: building recursive query; nslookup\n"));
+ if (qp->q_msg)
+ (void) free(qp->q_msg);
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ dprintf(1, (ddt, "resp: malloc error\n"));
+ goto servfail;
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, 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_int16_t)++nsid);
+ if (qp->q_fwd)
+ hp->rd = 1;
+ unsched(qp);
+ schedretry(qp, retrytime(qp));
+ nsa = Q_NEXTADDR(qp, 0);
+ dprintf(1, (ddt, "resp: forw -> [%s].%d ds=%d nsid=%d id=%d %dms\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), ds,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ (qp->q_addr[0].nsdata != NULL)
+ ? qp->q_addr[0].nsdata->d_nstime
+ : (-1)));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ if (sendto(ds, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "ns_resp: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ hp->rd = 0; /* leave set to 0 for dup detection */
+ nameserIncr(nsa->sin_addr, nssSentFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssRcvdFwdR);
+ dprintf(3, (ddt, "resp: Query sent.\n"));
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+formerr:
+ dprintf(3, (ddt,
+ "FORMERR resp() from [%s].%d size err %d, msglen %d\n",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ cp - msg, msglen));
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ (char*)dhash((u_char *)formerrmsg,
+ strlen(formerrmsg)
+ )
+ )
+ ) {
+ syslog(LOG_INFO, "Malformed response from [%s].%d (%s)\n",
+ inet_ntoa(from_addr.sin_addr),
+ ntohs(from_addr.sin_port),
+ formerrmsg);
+ }
+ nameserIncr(from_addr.sin_addr, nssSentFErr);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+return_msg:
+ nameserIncr(from_addr.sin_addr, nssRcvdFwdR);
+ nameserIncr(qp->q_from.sin_addr, nssSentFwdR);
+ /* 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);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+return_newmsg:
+ nameserIncr(qp->q_from.sin_addr, nssSentAns);
+ if (addcount) {
+ n = doaddinfo(hp, cp, buflen);
+ cp += n;
+ buflen -= n;
+ }
+ hp->qr = 1;
+ hp->id = qp->q_id;
+ hp->rd = 1;
+ hp->ra = 1;
+ (void) send_msg(newmsg, cp - newmsg, qp);
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+
+servfail:
+ nameserIncr(qp->q_from.sin_addr, nssSentFail);
+ 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((u_char *)hp, (cname ? qp->q_cmsglen : qp->q_msglen),
+ qp);
+ qremove(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return;
+}
+
+/*
+ * Decode the resource record 'rrp' and update the database.
+ * If savens is non-nil, record pointer for forwarding queries a second time.
+ */
+int
+doupdate(msg, msglen, rrp, zone, savens, flags, cred)
+ u_char *msg, *rrp;
+ struct databuf **savens;
+ int msglen, zone, flags;
+ u_int cred;
+{
+ register u_char *cp;
+ register int n;
+ int class, type, dlen, n1;
+ u_int32_t 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
+
+ dprintf(3, (ddt, "doupdate(zone %d, savens %x, flags %x)\n",
+ zone, savens, flags));
+
+ cp = rrp;
+ if ((n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname)) < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ dprintf(3, (ddt, "doupdate: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * Convert the resource record data into the internal
+ * database format.
+ */
+ switch (type) {
+ case T_A:
+ if (dlen != INT32SZ) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ /*FALLTHROUGH*/
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+ case T_NSAP:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 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 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ bcopy(cp, cp1, n = 5 * INT32SZ);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy(cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1,
+ sizeof data - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(1, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ 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 */
+ dprintf(1, (ddt, "UDPATE: REFUSED - SOA delete\n"));
+ 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)) {
+ dprintf(1,
+ (ddt,
+ "FORMERR UPDATE message length off\n"
+ )
+ );
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return (-1);
+ }
+ if (zones[zonenum].z_flags & 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;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ n = db_update(dname, dp, NULL, DB_MEXIST | DB_DELETE,
+ hashtab);
+ if (n != OK) {
+ dprintf(1, (ddt,
+ "UPDATE: db_update failed\n"));
+ free((char*) 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;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ 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((char*) dp);
+ /* Ok for UPDATEMA not to have deleted any RRs */
+ if (!DeletedOne && hp->opcode == UPDATEDA) {
+ dprintf(1, (ddt,
+ "UPDATE: db_update failed\n"));
+ 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) {
+ dprintf(1, (ddt,
+ "FORMERR UPDATE expand name failed\n"));
+ 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) {
+ dprintf(1, (ddt, "UPDATE: too much data\n"));
+ hp->rcode = NOCHANGE;
+ return (-1);
+ }
+ if (cp != (u_char *)(msg + msglen)) {
+ dprintf(1, (ddt,
+ "FORMERR UPDATE message length off\n"));
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ if ((zonenum = findzone(dname, class)) == 0) {
+ hp->rcode = NXDOMAIN;
+ return (-1);
+ }
+ if (zones[zonenum].z_flags & Z_DYNADDONLY) {
+ struct hashbuf *htp = hashtab;
+ char *fname;
+ if (nlookup(dname, &htp, &fname, 0) &&
+ !strcasecmp(dname, fname)) {
+ dprintf(1, (ddt,
+ "refusing add of existing name\n"
+ ));
+ hp->rcode = REFUSED;
+ return (-1);
+ }
+ }
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zonenum;
+ dp->d_cred = cred;
+ dp->d_clev = db_getclev(zones[zonenum].z_origin);
+ if ((n = db_update(dname, NULL, dp, DB_NODATA,
+ hashtab)) != OK) {
+ dprintf(1, (ddt, "UPDATE: db_update failed\n"));
+ hp->rcode = NOCHANGE;
+ free((char*) dp);
+ return (-1);
+ }
+ else
+ return (cp - rrp);
+ }
+#endif /* ALLOW_UPDATES */
+
+ if (zone == 0)
+ ttl += tt.tv_sec;
+#if defined(TRACEROOT) || defined(BOGUSNS)
+ if ((type == T_NS) && (savens != NULL)) {
+ char qname[MAXDNAME], *temp;
+ register int bogus = 0;
+ int bogusns = 0;
+#ifdef BOGUSNS
+ if (addr_on_netlist(from_addr.sin_addr, boglist)) {
+ bogusns++;
+ bogus++;
+ }
+#endif
+ if (!bogus &&
+ ((temp = strrchr((char *)data, '.')) != NULL) &&
+ !strcasecmp(temp, ".arpa")
+ )
+ bogus++;
+ qname[0] = qname[1] = '\0';
+ if (dn_expand(msg, msg + msglen, msg + HFIXEDSZ,
+ qname, sizeof(qname)) < 0)
+ qname[0] = '?';
+ else if (qname[0] == '\0')
+ qname[0] = '.';
+ if (bogus && ((dname[0] == '\0') && (zone == 0))) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "bogus root NS"))
+ syslog(LOG_NOTICE,
+ "bogus root NS %s rcvd from [%s] on query for \"%s\"",
+ data, inet_ntoa(from_addr.sin_addr),
+ qname);
+ return (cp - rrp);
+ }
+#ifdef BOGUSNS
+ if (bogusns) {
+ if (!haveComplained((char*)from_addr.sin_addr.s_addr,
+ "bogus nonroot NS"))
+ syslog(LOG_NOTICE,
+ "bogus nonroot NS %s rcvd from [%s] on query for \"%s\"",
+ data, inet_ntoa(from_addr.sin_addr),
+ qname);
+ return (cp - rrp);
+ }
+#endif
+ }
+#endif /*TRACEROOT || BOGUSNS*/
+
+ dp = savedata(class, type, ttl, cp1, n);
+ dp->d_zone = zone;
+ dp->d_cred = cred;
+ dp->d_clev = 0; /* We trust what is on disk more, except root srvrs */
+ if ((n = db_update(dname, dp, dp, flags, hashtab)) != OK) {
+#ifdef DEBUG
+ if (debug && (n != DATAEXISTS))
+ fprintf(ddt,"update failed (%d)\n", n);
+ else if (debug >= 3)
+ fprintf(ddt,"update failed (DATAEXISTS)\n");
+#endif
+ free((char *)dp);
+ } else if (type == T_NS && savens != NULL)
+ *savens = dp;
+ return (cp - rrp);
+}
+
+int
+send_msg(msg, msglen, qp)
+ u_char *msg;
+ int msglen;
+ struct qinfo *qp;
+{
+ if (qp->q_flags & 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) {
+ struct qinfo *tqp;
+
+ 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) {
+ if (!haveComplained((char*)qp->q_from.sin_addr.s_addr,
+ sendtoStr))
+ syslog(LOG_NOTICE,
+ "send_msg: sendto([%s].%d): %m",
+ inet_ntoa(qp->q_from.sin_addr),
+ ntohs(qp->q_from.sin_port));
+ nameserIncr(qp->q_from.sin_addr, nssSendtoErr);
+ return (1);
+ }
+ } else {
+ (void) writemsg(qp->q_stream->s_rfd, (u_char*)msg, msglen);
+ sq_done(qp->q_stream);
+ }
+ return (0);
+}
+
+#ifdef notdef
+/* i don't quite understand this but the only ref to it is notdef'd --vix */
+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 + HFIXEDSZ, (u_char *)dname,
+ sizeof(dname)) < 0)
+ return;
+ dprintf(2, (ddt, "prime: %s\n", dname));
+ (void) sysquery(dname, class, type, NULL, 0);
+}
+#endif
+
+void
+prime_cache()
+{
+ register struct qinfo *qp;
+
+ dprintf(1, (ddt, "prime_cache: priming = %d\n", priming));
+ if (!priming && fcachetab->h_tab[0] != NULL && !forward_only) {
+ priming++;
+ if ((qp = sysquery("", C_IN, T_NS, NULL, 0)) == NULL)
+ priming = 0;
+ else
+ qp->q_flags |= (Q_SYSTEM | Q_PRIMING);
+ }
+ needs_prime_cache = 0;
+ return;
+}
+
+struct qinfo *
+sysquery(dname, class, type, nss, nsc)
+ char *dname;
+ int class, type;
+ struct in_addr *nss;
+ int nsc;
+{
+ register struct qinfo *qp, *oqp;
+ register HEADER *hp;
+ struct namebuf *np;
+ struct databuf *nsp[NSMAX];
+ struct hashbuf *htp;
+ struct sockaddr_in *nsa;
+ char *fname;
+ int count;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ dprintf(3, (ddt, "sysquery(%s, %d, %d, 0x%x, %d)\n",
+ dname, class, type, nss, nsc));
+ qp = qnew();
+
+ if (nss && nsc) {
+ np = NULL;
+ } else {
+ htp = hashtab;
+ if (priming && dname[0] == '\0') {
+ np = NULL;
+ } else if ((np = nlookup(dname, &htp, &fname, 1)) == NULL) {
+ dprintf(1, (ddt,
+ "sysquery: nlookup error on %s?\n",
+ dname));
+ qfree(qp);
+ return (0);
+ }
+
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ case SERVFAIL:
+ dprintf(1, (ddt,
+ "sysquery: findns error on %s?\n", dname));
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ /* build new qinfo struct */
+ qp->q_cmsg = qp->q_msg = NULL;
+ qp->q_dfd = ds;
+ if (nss && nsc)
+ qp->q_fwd = NULL;
+ else
+ qp->q_fwd = fwdtab;
+ qp->q_expire = tt.tv_sec + RETRY_TIMEOUT*2;
+ qp->q_flags |= Q_SYSTEM;
+#ifdef LAME_DELEGATION
+ getname(np, qp->q_domain, sizeof(qp->q_domain));
+#endif /* LAME_DELEGATION */
+
+ if ((qp->q_msg = (u_char *)malloc(BUFSIZ)) == NULL) {
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ qp->q_msglen = res_mkquery(QUERY, dname, class,
+ type, NULL, 0, NULL,
+ qp->q_msg, BUFSIZ);
+ hp = (HEADER *) qp->q_msg;
+ hp->id = qp->q_nsid = htons((u_int16_t)++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
+ ) {
+ dprintf(3, (ddt, "sysquery: duplicate\n"));
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ if (nss && nsc) {
+ int i;
+ struct qserv *qs;
+
+ for (i = 0, qs = qp->q_addr;
+ i < nsc;
+ i++, qs++) {
+ qs->ns_addr.sin_family = AF_INET;
+ qs->ns_addr.sin_addr = nss[i];
+ qs->ns_addr.sin_port = ns_port;
+ qs->ns = NULL;
+ qs->nsdata = NULL;
+ qs->stime = tt;
+ qs->nretry = 0;
+ }
+ qp->q_naddr = nsc;
+ } else {
+ if ((count = nslookup(nsp, qp, dname, "sysquery")) <= 0) {
+ if (count < 0) {
+ dprintf(1, (ddt,
+ "sysquery: nslookup reports danger\n"));
+ } else {
+ dprintf(1, (ddt,
+ "sysquery: no addrs found for NS's\n"));
+ }
+ qfree(qp);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (0);
+ }
+ }
+
+ schedretry(qp, retrytime(qp));
+ if (qp->q_fwd == NULL)
+ qp->q_addr[0].stime = tt; /* XXX - why not every? */
+ nsa = Q_NEXTADDR(qp, 0);
+
+ dprintf(1, (ddt,
+ "sysquery: send -> [%s].%d dfd=%d nsid=%d id=%d retry=%ld\n",
+ inet_ntoa(nsa->sin_addr),
+ ntohs(nsa->sin_port), qp->q_dfd,
+ ntohs(qp->q_nsid), ntohs(qp->q_id),
+ qp->q_time));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(qp->q_msg, ddt);
+#endif
+ if (sendto(qp->q_dfd, qp->q_msg, qp->q_msglen, 0,
+ (struct sockaddr *)nsa,
+ sizeof(struct sockaddr_in)) < 0) {
+ if (!haveComplained((char*)nsa->sin_addr.s_addr, sendtoStr))
+ syslog(LOG_NOTICE, "sysquery: sendto([%s].%d): %m",
+ inet_ntoa(nsa->sin_addr), ntohs(nsa->sin_port));
+ nameserIncr(nsa->sin_addr, nssSendtoErr);
+ }
+ nameserIncr(nsa->sin_addr, nssSentSysQ);
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return (qp);
+}
+
+/*
+ * Check the list of root servers after receiving a response
+ * to a query for the root servers.
+ */
+static void
+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++;
+ dprintf(1, (ddt, "%d root servers\n", count));
+ 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) {
+ dprintf(1, (ddt, "deleting old root server '%s'\n",
+ dp->d_data));
+ 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
+ */
+static void
+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;
+
+ dprintf(2, (ddt, "check_ns()\n"));
+
+ curtime = (u_int32_t) 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 = (caddr_t) dp->d_data;
+ htp = hashtab;
+ tnp = nlookup(dname, &htp, &fname, 0);
+ if (tnp == NULL || fname != dname) {
+ dprintf(3, (ddt,
+ "check_ns: %s: not found %s %x\n",
+ dname, fname, tnp));
+ sysquery(dname, dp->d_class, T_A, NULL, 0);
+ 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)) {
+ dprintf(3, (ddt,
+ "check_ns: stale entry '%s'\n",
+ tnp->n_dname));
+ /* 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, NULL, 0);
+ }
+ }
+}
+
+/* int findns(npp, class, nsp, countp, flag)
+ * Find NS' or an SOA
+ * npp, class:
+ * dname whose least-superior NS is wanted
+ * nsp, countp:
+ * result array and count; array will also be NULL terminated
+ * flag:
+ * boolean: we're being called from ADDAUTH, bypass authority checks
+ * return value:
+ * NXDOMAIN: we are authoritative for this {dname,class}
+ * SERVFAIL: we are auth but zone isn't loaded; or, no root servers found
+ * OK: success (this is the only case where *countp and nsp[] are valid)
+ */
+int
+findns(npp, class, nsp, countp, flag)
+ register struct namebuf **npp;
+ int class;
+ struct databuf **nsp;
+ int *countp;
+ int flag;
+{
+ register struct namebuf *np = *npp;
+ register struct databuf *dp;
+ register struct databuf **nspp;
+ struct hashbuf *htp;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+
+ if (priming && (np == NULL || np->n_dname[0] == '\0'))
+ htp = fcachetab;
+ else
+ htp = hashtab;
+
+try_again:
+ if (htp == fcachetab)
+ needs_prime_cache = 1;
+ while (np == NULL && htp != NULL) {
+ dprintf(3, (ddt, "findns: using %s\n",
+ htp == hashtab ? "cache" : "hints"));
+ 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) {
+ dprintf(5, (ddt, "findns: np 0x%x '%s'\n", np, np->n_dname));
+ /* Look first for SOA records. */
+#ifdef ADDAUTH
+ if (!flag)
+#endif
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (dp->d_zone != 0 && match(dp, class, T_SOA)) {
+ dprintf(3, (ddt, "findns: SOA found\n"));
+ if (zones[dp->d_zone].z_flags & Z_AUTH) {
+ *npp = np;
+ nsp[0] = dp;
+#ifdef DATUMREFCNT
+ nsp[1] = NULL;
+ dp->d_rcnt++;
+#endif
+ return (NXDOMAIN);
+ } else {
+ /* XXX: zone isn't loaded but we're
+ * primary or secondary for it.
+ * should we fwd this?
+ */
+ 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 (!match(dp, class, T_NS))
+ continue;
+ /*
+ * Don't use records that may become invalid to
+ * reference later when we do the rtt computation.
+ * Never delete our safety-belt information!
+ *
+ * XXX: this is horribly bogus.
+ */
+ if ((dp->d_zone == 0) &&
+ (dp->d_ttl < (tt.tv_sec+900)) &&
+ !(dp->d_flags & DB_F_HINT)) {
+ dprintf(1, (ddt, "findns: stale entry '%s'\n",
+ np->n_dname));
+ /* 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;
+#ifdef DATUMREFCNT
+ dp->d_rcnt++;
+#endif
+ }
+ }
+
+ *countp = nspp - nsp;
+ if (*countp > 0) {
+ dprintf(3, (ddt, "findns: %d NS's added for '%s'\n",
+ *countp, np->n_dname));
+ *nspp = NULL;
+ *npp = np;
+ return (OK); /* Success, got some NS's */
+ }
+try_parent:
+ np = np->n_parent;
+ }
+ if (htp)
+ goto try_again;
+ dprintf(1, (ddt, "findns: No root nameservers for class %s?\n",
+ p_class(class)));
+ if ((unsigned)class < MAXCLASS && norootlogged[class] == 0) {
+ norootlogged[class] = 1;
+ syslog(LOG_ERR, "No root nameservers for class %s\n",
+ p_class(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.
+ */
+int
+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;
+
+#ifdef ROUND_ROBIN
+ if (type != T_ANY && type != T_PTR) {
+ /* cycle order of RRs, for a load balancing effect... */
+
+ register struct databuf **dpp;
+
+ for (dpp = &np->n_data; dp = *dpp; dpp = &dp->d_next) {
+ if (dp->d_next && wanted(dp, class, type)) {
+ register struct databuf *lp;
+
+ *dpp = lp = dp->d_next;
+ dp->d_next = NULL;
+
+ for (dpp = &lp->d_next;
+ *dpp;
+ dpp = &lp->d_next)
+ lp = *dpp;
+ *dpp = dp;
+ break;
+ }
+ }
+ }
+#endif /*ROUND_ROBIN*/
+
+ buflen = *lenp;
+ cp = ((char *)hp) + *countp;
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+#ifndef NCACHE /*if no negative caching then cname => nothing else*/
+ if (type == T_CNAME && class == dp->d_class) {
+ /* any data means no CNAME exists */
+ *countp = 0;
+ return 0;
+ }
+#endif /*NCACHE*/
+ 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.
+ */
+ dprintf(3, (ddt,
+ "finddata: stale entry '%s'\n",
+ np->n_dname));
+ if (dp->d_zone == 0)
+ foundstale++;
+ continue;
+ }
+ if (dp->d_cred == DB_C_ADDITIONAL) {
+ /* we want to expire additional data very
+ * quickly. current strategy is to cut 5%
+ * off each time it is accessed. this makes
+ * stale(dp) true faster when this datum is
+ * used often.
+ */
+ dp->d_ttl = tt.tv_sec
+ +
+ 0.95 * (int) (dp->d_ttl - tt.tv_sec);
+ }
+#ifdef NCACHE
+ /* -ve $ing stuff, anant@isi.edu
+ * if we have a -ve $ed record, change the rcode on the
+ * header to reflect that
+ */
+ if (dp->d_rcode == NOERROR_NODATA) {
+ if (count != 0) {
+ /*
+ * This should not happen, yet it does...
+ */
+ syslog(LOG_WARNING,
+ "NODATA & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ if (type != T_ANY) {
+ hp->rcode = NOERROR_NODATA;
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ /* don't satisfy T_ANY queries from -$ info */
+ continue;
+ }
+#ifndef RETURNSOA
+ if (dp->d_rcode == NXDOMAIN) {
+ if (count != 0) {
+ /*
+ * This should not happen, yet it might...
+ */
+ syslog(LOG_WARNING,
+ "NXDOMAIN & data for \"%s\" type %d class %d",
+ *dnamep, type, class);
+ continue;
+ }
+ if (type != T_ANY) {
+ hp->rcode = NXDOMAIN;
+ *countp = 0;
+ return 1; /* XXX - we have to report success */
+ }
+ /* don't satisfy T_ANY queries from -$ info */
+ continue;
+ }
+#endif
+#endif /*NCACHE*/
+
+ if ((n = make_rr(*dnamep, dp, (u_char *)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_flags & Z_AUTH) &&
+ class != C_ANY)
+ hp->aa = 1; /* XXX */
+#endif
+ if (dp->d_type == T_CNAME) {
+ if (type != T_ANY) { /* or T_NS? */
+ *dnamep = (caddr_t) dp->d_data;
+ if (dp->d_zone &&
+ (zones[dp->d_zone].z_flags & 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);
+ /* XXX this isn't right if 'type' is something special
+ * such as T_AXFR or T_MAILB, since the matching done
+ * by match() in delete_all() is different from that
+ * done by wanted() above.
+ */
+ }
+ dprintf(3, (ddt, "finddata: added %d class %d type %d RRs\n",
+ count, class, type));
+ *countp = count;
+ return (*lenp - buflen);
+}
+
+/*
+ * Do we want this data record based on the class and type?
+ */
+int
+wanted(dp, class, type)
+ struct databuf *dp;
+ int class, type;
+{
+
+ dprintf(3, (ddt, "wanted(%x, %d, %d) %d, %d\n", dp, class, type,
+ dp->d_class, dp->d_type));
+
+ if (dp->d_class != class && class != C_ANY)
+ return (0);
+ if (type == dp->d_type)
+ return (1);
+#ifdef NCACHE
+ /*-ve $ing stuff, for a T_ANY query, we do not want to return
+ * -ve $ed RRs.
+ */
+ if (type == T_ANY && dp->d_rcode == NOERROR_NODATA)
+ return (0);
+#endif
+
+ switch (dp->d_type) {
+ case T_ANY:
+ return (1);
+ case T_CNAME:
+#ifdef NCACHE
+ if (dp->d_rcode != NOERROR_NODATA)
+#endif
+ return (1);
+#ifdef NCACHE
+ else
+ break;
+#endif
+ }
+ 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:
+ /* T_AXFR needs an authoritative SOA */
+ if (dp->d_type == T_SOA && dp->d_zone != 0
+ && (zones[dp->d_zone].z_flags & Z_AUTH))
+ return (1);
+ break;
+ }
+ 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.
+ */
+int
+add_data(np, dpp, cp, buflen)
+ struct namebuf *np;
+ struct databuf **dpp;
+ register u_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 */
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ 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.
+ */
+void
+delete_all(np, class, type)
+ register struct namebuf *np;
+ int class, type;
+{
+ register struct databuf *dp, *pdp;
+
+ dprintf(3, (ddt, "delete_all: '%s' 0x%x class %d type %d\n",
+ np->n_dname, np, class, type));
+ 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 0000000..c35b58f
--- /dev/null
+++ b/usr.sbin/named/ns_sort.c
@@ -0,0 +1,169 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_sort.c 4.10 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: ns_sort.c,v 4.9.1.6 1994/07/23 23:23:56 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986, 1990
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <resolv.h>
+
+#include "named.h"
+
+static int sort_rr __P((u_char *cp, int count, struct netinfo *ntp, u_char *eom));
+
+struct netinfo *
+local(from)
+ struct sockaddr_in *from;
+{
+ 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->addr == (from->sin_addr.s_addr & ntp->mask))
+ return (ntp);
+ }
+ return (NULL);
+}
+
+void
+sort_response(cp, ancount, lp, eom)
+ register u_char *cp;
+ register int ancount;
+ struct netinfo *lp;
+ u_char *eom;
+{
+ register struct netinfo *ntp;
+
+ dprintf(3, (ddt, "sort_response(%d)\n", ancount));
+ if (ancount > 1) {
+ if (sort_rr(cp, ancount, lp, eom))
+ return;
+ for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+ if ((ntp->addr == lp->addr) && (ntp->mask == lp->mask))
+ continue;
+ if (sort_rr(cp, ancount, ntp, eom))
+ break;
+ }
+ }
+}
+
+static 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->addr;
+ fprintf(ddt, "sort_rr(x%x, %d, [%s])\n",
+ cp, count, inet_ntoa(inaddr));
+ }
+#endif
+ 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 += INT32SZ;
+ 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, INADDRSZ);
+ if (rr1 == NULL)
+ rr1 = cp;
+ if ((ntp->mask & inaddr.s_addr) == ntp->addr) {
+ dprintf(2, (ddt,"net [%s] best choice\n",
+ inet_ntoa(inaddr)));
+ if (rr1 != cp) {
+ bcopy(rr1, cp, INADDRSZ);
+ bcopy((char *)&inaddr, rr1, INADDRSZ);
+ }
+ 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 0000000..d6d6225
--- /dev/null
+++ b/usr.sbin/named/ns_stats.c
@@ -0,0 +1,325 @@
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)ns_stats.c 4.10 (Berkeley) 6/27/90";
+static char rcsid[] = "$Id: ns_stats.c,v 4.9.1.7 1994/06/06 09:08:15 vixie Exp $";
+#endif /* not lint */
+
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/**************************************************************************/
+/* simple monitoring of named behavior */
+/* dumps a bunch of values into a well-known file */
+/**************************************************************************/
+
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <errno.h>
+
+#include "named.h"
+#include "tree.h"
+
+static u_long typestats[T_ANY+1];
+static const 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", "RP", "AFSDB", "X25",
+ "ISDN", "RT", "NSAP", 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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,
+ /* 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"
+};
+
+static void nameserStats __P((FILE *));
+
+void
+ns_stats()
+{
+ time_t timenow;
+ register FILE *f;
+ register int i;
+
+ if (!(f = fopen(statsfile, "a"))) {
+ dprintf(1, (ddt, "can't open stat file, \"%s\"\n", statsfile));
+ syslog(LOG_ERR, "cannot open stat file, \"%s\"\n", statsfile);
+ return;
+ }
+
+ time(&timenow);
+ fprintf(f, "+++ Statistics Dump +++ (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ fprintf(f, "%d\ttime since boot (secs)\n", timenow - boottime);
+ fprintf(f, "%d\ttime since reset (secs)\n", timenow - resettime);
+
+#ifdef DMALLOC
+ /* malloc statistics */
+ dmallocstats(f);
+#endif
+
+ /* 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);
+
+ /* name server statistics */
+ nameserStats(f);
+
+ fprintf(f, "--- Statistics Dump --- (%ld) %s",
+ (long)timenow, ctime(&timenow));
+ (void) my_fclose(f);
+}
+
+void
+qtypeIncr(qtype)
+ int qtype;
+{
+ if (qtype < T_A || qtype > T_ANY)
+ qtype = 0; /* bad type */
+ typestats[qtype]++;
+}
+
+static tree *nameserTree;
+static int nameserInit;
+
+#ifdef STATS
+static FILE *nameserStatsFile;
+static u_long globalStats[nssLast];
+static const char *statNames[nssLast] = {
+ "RQ", /* sent us a query */
+ "RR", /* sent us an answer */
+ "RIQ", /* sent us an inverse query */
+ "RNXD", /* sent us a negative response */
+ "RFwdQ", /* sent us a query we had to fwd */
+ "RFwdR", /* sent us a response we had to fwd */
+ "RDupQ", /* sent us a retry */
+ "RDupR", /* sent us an extra answer */
+ "RFail", /* sent us a SERVFAIL */
+ "RFErr", /* sent us a FORMERR */
+ "RErr", /* sent us some other error */
+ "RTCP", /* sent us a query using TCP */
+ "RAXFR", /* sent us an AXFR */
+ "RLame", /* sent us a lame delegation */
+ "ROpts", /* sent us some IP options */
+ "SSysQ", /* sent them a sysquery */
+ "SAns", /* sent them an answer */
+ "SFwdQ", /* fwdd a query to them */
+ "SFwdR", /* fwdd a response to them */
+ "SDupQ", /* sent them a retry */
+ "SFail", /* sent them a SERVFAIL */
+ "SFErr", /* sent them a FORMERR */
+ };
+#endif /*STATS*/
+
+static int
+nameserCompar(t1, t2)
+ const tree_t t1, t2;
+{
+ u_int32_t a1 = ntohl(((struct nameser *)t1)->addr.s_addr),
+ a2 = ntohl(((struct nameser *)t2)->addr.s_addr);
+
+ if (a1 < a2)
+ return (-1);
+ else if (a1 > a2)
+ return (1);
+ else
+ return (0);
+}
+
+struct nameser *
+nameserFind(addr, flags)
+ struct in_addr addr;
+ int flags;
+{
+ struct nameser dummy;
+ struct nameser *ns;
+
+ if (!nameserInit) {
+ tree_init(&nameserTree);
+ nameserInit++;
+ }
+
+ dummy.addr = addr;
+ ns = (struct nameser *)tree_srch(&nameserTree, nameserCompar,
+ (tree_t)&dummy);
+ if (!ns && (flags & NS_F_INSERT)) {
+ ns = (struct nameser *)malloc(sizeof(struct nameser));
+ if (!ns) {
+ nomem: if (!haveComplained("nameserFind complaint", ""))
+ syslog(LOG_NOTICE,
+ "nameserFind: malloc failed; %m");
+ return (NULL);
+ }
+ memset(ns, 0, sizeof(struct nameser));
+ ns->addr = addr;
+ if (!tree_add(&nameserTree, nameserCompar, (tree_t)ns, NULL)) {
+ int save = errno;
+ free(ns);
+ errno = save;
+ goto nomem;
+ }
+ }
+ return (ns);
+}
+
+
+void
+nameserIncr(addr, which)
+ struct in_addr addr;
+ enum nameserStats which;
+{
+#ifdef STATS
+ struct nameser *ns = nameserFind(addr, NS_F_INSERT);
+
+ if ((int)which < (int)nssLast) {
+ if (ns)
+ ns->stats[(int)which]++;
+ globalStats[(int)which]++;
+ } else {
+ syslog(LOG_DEBUG, "nameserIncr([%d], %d): bad 'which'",
+ inet_ntoa(addr), (int)which);
+ }
+#endif /*STATS*/
+}
+
+#ifdef STATS
+static void
+nameserStatsOut(f, stats)
+ FILE *f;
+ u_long stats[];
+{
+ int i;
+ char *pre = "\t";
+
+ for (i = 0; i < (int)nssLast; i++) {
+ fprintf(f, "%s%u", pre, stats[i]);
+ pre = ((i+1) % 5) ? " " : " ";
+ }
+ fputc('\n', f);
+}
+
+static void
+nameserStatsHdr(f)
+ FILE *f;
+{
+ int i;
+ char *pre = "\t";
+
+ fprintf(f, "(Legend)\n");
+ for (i = 0; i < (int)nssLast; i++) {
+ fprintf(f, "%s%s", pre,
+ statNames[i] ? statNames[i] : "");
+ pre = ((i+1) % 5) ? "\t" : "\n\t";
+ }
+ fputc('\n', f);
+}
+
+static int
+nameserStatsTravUAR(t)
+ tree_t t;
+{
+ struct nameser *ns = (struct nameser *)t;
+
+ fprintf(nameserStatsFile, "[%s]\n", /* : rtt %u */
+ inet_ntoa(ns->addr) /*, ns->rtt*/ );
+ nameserStatsOut(nameserStatsFile, ns->stats);
+ return (1);
+}
+#endif /*STATS*/
+
+static void
+nameserStats(f)
+ FILE *f;
+{
+#ifndef STATS
+ fprintf(f, "<<No nameserver statistics in this server>>\n");
+#else
+ nameserStatsFile = f;
+ fprintf(f, "++ Name Server Statistics ++\n");
+ nameserStatsHdr(f);
+ fprintf(f, "(Global)\n");
+ nameserStatsOut(f, globalStats);
+ tree_trav(&nameserTree, nameserStatsTravUAR);
+ fprintf(f, "-- Name Server Statistics --\n");
+ nameserStatsFile = NULL;
+#endif /*STATS*/
+}
diff --git a/usr.sbin/named/ns_validate.c b/usr.sbin/named/ns_validate.c
new file mode 100644
index 0000000..f1236c5
--- /dev/null
+++ b/usr.sbin/named/ns_validate.c
@@ -0,0 +1,1161 @@
+/**************************************************************************
+ * ns_validate.c (was security.c in original ISI contribution)
+ * author: anant kumar
+ * contributed: March 17, 1993
+ *
+ * implements validation procedure for RR's received from a server as a
+ * response to a query.
+ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <syslog.h>
+#include <errno.h>
+#include <stdio.h>
+#include <resolv.h>
+
+#include "named.h"
+
+#ifdef VALIDATE
+
+static int isvalid __P((struct namebuf *, int, int, char *, int)),
+ check_addr_ns __P((struct databuf **,
+ struct sockaddr_in *,
+ char *)),
+ check_in_tables __P((struct databuf **,
+ struct sockaddr_in *,
+ char *));
+#if 0
+static void stick_in_queue __P((char *, int, int, char *));
+#endif
+
+static NAMEADDR nameaddrlist[MAXNAMECACHE];
+static int firstNA = 0,
+ lastNA = 0;
+
+static TO_Validate *validateQ, *currentVQ;
+static int VQcount;
+
+/*****************************************************************
+ * validate() is called from dovalidate(). it takes as parameters,
+ * the domain name sought, the class, type etc. of record, the server
+ * that gave us the answer and the data it gave us
+ *
+ * it returns VALID if it is able to validate the record, INVALID if it cannot.
+ * furtehr VALID is split into VALID_CACHE if we need to cache this record
+ * since the domainname is not something we are authoritative for and
+ * VALID_NO_CACHE if the name is something we are authoritative for.
+ *
+ * pseudocode for function validate is as follows:
+ * validate(domain, server, type, class, data, dlen, rcode) {
+ *
+ * if(dname or a higher level name not found in cache)
+ * return INVALID;
+ * if (NS records for "domain" found in cache){
+ *
+ * if(we are authoritative) /findns() returned NXDOMAIN;/
+ * if(we did not have an exact match on names)
+ * =>the name does not exist in our database
+ * => data is bad: return INVALID
+ * if(data agrees with what we have)
+ * return VALID_NO_CACHE;
+ * else return INVALID;
+ *
+ * if(we are not authoritative) /findns() returned OK;/
+ * if (address records for NS's found in cache){
+ * if("server" = one of the addresses){
+ * return VALID_CACHE;
+ * }else{
+ * stick in queue of "to_validate" data;
+ * return (INVALID);
+ * }
+ * else return INVALID;
+ *
+ * This performs the validation procedure described above. Checks
+ * for the longest component of the dname that has a NS record
+ * associated with it. At any stage, if no data is found, it implies
+ * that the name is bad (has an unknown domain identifier) thus, we
+ * return INVALID.
+ * If address of one of these servers matches the address of the server
+ * that returned us this data, we are happy!
+ *
+ * since findns will set needs_prime_cache if np = NULL is passed, we always
+ * reset it. will let ns_req do it when we are searching for ns records to
+ * query someone. hence in all the three cases of switch(findns())
+ * we have needs_prime_cache = 0;
+ *****************************************************************************/
+int
+validate(dname, server, type, class, data, dlen
+#ifdef NCACHE
+ ,rcode
+#endif
+ )
+ char *dname;
+ struct sockaddr_in *server;
+ int type;
+ int class;
+ char *data;
+ int dlen;
+#ifdef NCACHE
+ int rcode;
+#endif
+{
+ struct namebuf *np, *dnamep;
+ struct hashbuf *htp;
+ struct databuf *nsp[NSMAX];
+ int count;
+ char *fname;
+ int exactmatch = 0;
+ struct fwdinfo *fwd;
+
+#ifdef DATUMREFCNT
+ nsp[0] = NULL;
+#endif
+ dprintf(3, (ddt,
+ "validate(), d:%s, s:[%s], t:%d, c:%d\n",
+ dname, inet_ntoa(server->sin_addr), type, class));
+
+ /* everything from forwarders is the GOSPEL */
+ for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) {
+ if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr)
+ return(VALID_CACHE);
+ }
+
+ htp = hashtab;
+ if (priming && (dname[0] == '\0'))
+ np = NULL;
+ else
+ np = nlookup(dname, &htp, &fname, 0);
+
+ /* we were able to locate namebufs for this domain, or a parent domain,
+ * or ??? */
+
+ if (np == NULL) {
+ fname = (char *)malloc(1);
+ fname[0] = '\0';
+ }
+ dprintf(5, (ddt,
+ "validate:namebuf found np:0x%x, d:\"%s\", f:\"%s\"\n",
+ np, dname, fname));
+ /* save the namebuf if we were able to locate the exact dname */
+ if (!strcasecmp(dname, fname)) {
+ dnamep = np;
+ exactmatch = 1;
+ }
+ if (np == NULL && fname != NULL) {
+ free((char *)fname);
+ }
+ switch (findns(&np, class, nsp, &count, 0)) {
+ case NXDOMAIN:
+ /** we are authoritative for this domain, lookup name
+ * in our zone data, if it matches, return valid.
+ * in either case, do not cache
+ **/
+ dprintf(5, (ddt, "validate: auth data found\n"));
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+
+#ifdef NCACHE
+ if(rcode == NXDOMAIN) {
+ /* If we had an exactmatch on the name, we found the
+ * name in our authority database, so this couldn't
+ * have been a bad name. INVALID data, say so
+ */
+ if (exactmatch)
+ return INVALID;
+ else
+ /* we did not have an exactmatch, the data is
+ * good, we do not NCACHE stuff we are
+ * authoritative for, though.
+ */
+ return VALID_NO_CACHE;
+ }
+#endif
+ if (!strcasecmp(dname, np->n_dname)) {
+
+ /* if the name we seek is the same as that we have ns
+ * records for, compare the data we have to see if it
+ * matches. if it does, return valid_no_cache, if it
+ * doesn't, invalid.
+ */
+ if (isvalid(np, type, class, data, dlen))
+ return VALID_NO_CACHE;
+ else
+ return INVALID;
+ }
+
+ /* we found ns records in a higher level, if we were unable to
+ * locate the exact name earlier, it means we are
+ * authoritative for this domain but do not have records for
+ * this name. this name is obviously invalid
+ */
+ if (!exactmatch)
+ return INVALID;
+
+ /* we found the exact name earlier and we are obviously
+ * authoritative so check for data records and see if any
+ * match.
+ */
+ if (isvalid(dnamep, type, class, data, dlen))
+ return VALID_NO_CACHE;
+ else
+ return INVALID;
+
+ case SERVFAIL:/* could not find name server records*/
+ /* stick_in_queue(dname, type, class, data); */
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+
+ case OK: /*proceed */
+ dprintf(5,
+ (ddt,
+ "validate:found ns records:calling check_addr_ns\n"));
+ if (needs_prime_cache)
+ needs_prime_cache = 0;
+ if (check_addr_ns(nsp, server, dname)) {
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return VALID_CACHE;
+ }
+ /* server is not one of those we know of */
+ /* stick_in_queue(dname, type, class, data); */
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+ default:
+#ifdef DATUMREFCNT
+ free_nsp(nsp);
+#endif
+ return INVALID;
+ } /*switch*/
+
+} /*validate*/
+
+/***********************************************************************
+ * validate rr returned by somebody against your own database, if you are
+ * authoritative for the information. if you have a record that matches,
+ * return 1, else return 0. validate() above will use this and determine
+ * if the record should be returned/discarded.
+ ***********************************************************************/
+static int
+isvalid(np, type, class, data, dlen)
+ struct namebuf *np;
+ int type, class;
+ char *data;
+ int dlen;
+{
+ register struct databuf *dp;
+
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (!wanted(dp, class, type)) {
+ if ((type == T_CNAME) && (class == dp->d_class)) {
+ /* if a cname exists, any other will not */
+ return(0);
+ /* we come here only for zone info,
+ * so -ve $ed info can't be
+ */
+ }
+ continue;
+ }
+ /* type and class match, if i get here
+ * let's now compare the data section, per RR type
+ */
+
+ /* unless, of course, the data was negative, in which case
+ * we should return FAILURE since we should not have found
+ * data here.
+ */
+ if ((data == NULL) || (dlen == 0)) {
+ return 0;
+ }
+
+ /* XXX: why aren't we just calling db_cmp() ?
+ */
+
+ switch (type) {
+ char *td;
+ u_char *tdp;
+ int x;
+
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ x = memcmp(dp->d_data, data, dlen);
+ dprintf(3, (ddt, "type = %d, GOOD = %d\n",
+ type, x));
+ if (x == 0)
+ return (1);
+ else
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ x = strncasecmp((char *)dp->d_data, data, dlen);
+ dprintf(3, (ddt, "type = %d, GOOD = %d\n",
+ type, x));
+ if (x == 0)
+ return (1);
+ else
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ /* compare first string */
+ x = strncasecmp((char *)dp->d_data, data,
+ strlen(data) + 1);
+ if (x != 0)
+ break;
+
+ /* move to second string */
+ td = data + (strlen(data) + 1);
+ tdp = dp->d_data +
+ (strlen((char *)dp->d_data)+1);
+
+ /* compare second string */
+ x = strncasecmp(td, (char *)tdp,
+ strlen((char *)td+1));
+ if (x != 0)
+ break;
+
+ /* move beyond second string, to
+ * set of words in SOA.
+ * RP and MINFO stuff really
+ * ends here
+ */
+
+ td = td + strlen((char *)td) + 1;
+ tdp = tdp + strlen((char *)tdp) + 1;
+ if (type == T_SOA) {
+ x = memcmp(td, (char *)tdp,
+ 5*INT32SZ);
+ if (x != 0)
+ break;
+ }
+
+ /* everything was equal, wow!
+ * so return a success
+ */
+ return (1);
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ x = memcmp(dp->d_data, data,
+ INT16SZ);
+ if (x != 0)
+ break;
+ td = data + INT16SZ;
+ tdp = dp->d_data + INT16SZ;
+ x = strncasecmp(td, (char *)tdp,
+ strlen((char *)td) + 1);
+ if (x != 0)
+ break;
+ return (1);
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return (0);
+ }
+ /* continue in loop if record did not match */
+ }
+ /* saw no record of interest in whole chain
+ * If the data we were trying to validate was negative, we succeeded!
+ * else we failed
+ */
+ if ((data == NULL) || (dlen == 0)) {
+ /* negative data, report success */
+ return 1;
+ }
+ /* positive data, no such RR, validation failed */
+ return (0);
+}
+
+/******************************************************************
+ * get a list of databufs that have ns addresses for the closest domain
+ * you know about, get their addresses and confirm that server indeed
+ * is one of them. if yes return 1 else 0.
+ * first checks the cache that we build in nslookup() earlier
+ * when we ns_forw(). if unableto find it there, it checks the entire
+ * hash table to do address translations.
+ *******************************************************************/
+static int
+check_addr_ns(nsp, server, dname)
+ struct databuf **nsp;
+ struct sockaddr_in *server;
+ char *dname;
+{
+ int i, found=0;
+ char sname[MAXDNAME];
+ struct in_addr *saddr = &(server->sin_addr);
+ struct databuf **nsdp;
+
+ dprintf(5, (ddt,
+ "check_addr_ns: s:[%s], db:0x%x, d:\"%s\"\n",
+ inet_ntoa(*saddr), nsp, dname));
+
+ for(i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) {
+ if (!bcmp((char *)saddr,
+ (char *)&(nameaddrlist[i].ns_addr),
+ INADDRSZ)) {
+ strcpy(sname, nameaddrlist[i].nsname);
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ dprintf(3, (ddt,
+ "check_addr_ns: found address:[%s]\n",
+ inet_ntoa(*saddr)));
+ for (nsdp = nsp; *nsdp != NULL;nsdp++) {
+ dprintf(5, (ddt,
+ "check_addr_ns:names are:%s, %s\n",
+ sname,(*nsdp)->d_data));
+ if (!strcasecmp(sname,(char *)((*nsdp)->d_data))) {
+ return (1);
+ }
+ }
+ }
+ /* could not find name in my cache of servers, must go through the
+ * whole grind
+ */
+
+ dprintf(2, (ddt, "check_addr_ns:calling check_in_tables()\n"));
+ return (check_in_tables(nsp, server, dname));
+}
+
+/*************************************************************************
+ * checks in hash tables for the address of servers whose name is in the
+ * data section of nsp records. borrows code from nslookup()/ns_forw.c
+ * largely.
+ *************************************************************************/
+static int
+check_in_tables(nsp, server, syslogdname)
+ struct databuf *nsp[];
+ struct sockaddr_in *server;
+ char *syslogdname;
+{
+ register struct namebuf *np;
+ register struct databuf *dp, *nsdp;
+ struct hashbuf *tmphtp;
+ char *dname, *fname;
+ int class;
+ int qcomp();
+
+ dprintf(3, (ddt, "check_in_tables(nsp=x%x,qp=x%x,'%s')\n",
+ nsp, server, syslogdname));
+
+ while ((nsdp = *nsp++) != NULL) {
+ class = nsdp->d_class;
+ dname = (char *)nsdp->d_data;
+ dprintf(3, (ddt, "check_in_tables: NS %s c%d t%d (x%x)\n",
+ dname, class, nsdp->d_type, nsdp->d_flags));
+ tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);
+ np = nlookup(dname, &tmphtp, &fname, 1);
+ if (np == NULL || fname != dname) {
+ dprintf(3, (ddt, "%s: not found %s %x\n",
+ dname, fname, np));
+ continue;
+ }
+ /* look for name server addresses */
+ for (dp = np->n_data; dp != NULL; dp = dp->d_next) {
+ if (stale(dp))
+ continue;
+ if (dp->d_type != T_A || dp->d_class != class)
+ continue;
+#ifdef NCACHE
+ if (dp->d_rcode)
+ continue;
+#endif
+ if (!bcmp((char *)dp->d_data,
+ (char *)&(server->sin_addr),
+ INADDRSZ)) {
+ return (1);
+ }
+ }
+ }
+ return (0); /* haven't been able to locate the right address */
+}
+
+/************************************************************************
+ * is called in nslookup() and stores the name vs address of a name server
+ * --& check_in_tables above--
+ * we contact, in a list of a maximum MAXNAMECACHE entries. we later refer
+ * -- NAMEADDR nameaddrlist[MAXNAMECACHE]; --
+ * to this list when we are trying to resolve the name in check_addr_ns().
+ *************************************************************************/
+void
+store_name_addr(servername, serveraddr, syslogdname, sysloginfo)
+ char *servername;
+ struct in_addr *serveraddr;
+ char *syslogdname;
+ char *sysloginfo;
+{
+ int i;
+
+ dprintf(3, (ddt,
+ "store_name_addr:s:%s, a:[%s]\n",
+ servername, inet_ntoa(*serveraddr)));
+
+ /* if we already have the name address pair in cache, return */
+ for (i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) {
+ if (strcasecmp(servername, nameaddrlist[i].nsname) == 0) {
+ if (serveraddr->s_addr
+ ==
+ nameaddrlist[i].ns_addr.s_addr) {
+ dprintf(5, (ddt,
+ "store_name_addr:found n and a [%s] [%s] in our $\n",
+ inet_ntoa(nameaddrlist[i].ns_addr),
+ inet_ntoa(*serveraddr)));
+ return;
+ } /* if */
+ } else if (serveraddr->s_addr
+ ==
+ nameaddrlist[i].ns_addr.s_addr) {
+#ifdef BAD_IDEA
+ /*
+ * log this as it needs to be fixed.
+ * replace old name by new, next query likely to have
+ * NS record matching new
+ */
+ if (!haveComplained(
+ (char*)dhash((u_char*)nameaddrlist[i].nsname,
+ strlen(nameaddrlist[i].nsname)),
+ (char*)dhash((u_char*)servername,
+ strlen(servername))
+ )
+ ) {
+ syslog(LOG_INFO,
+ "%s: server name mismatch for [%s]: (%s != %s) (server for %s)",
+ sysloginfo,
+ inet_ntoa(*serveraddr),
+ nameaddrlist[i].nsname, servername,
+ syslogdname);
+ }
+#endif
+ free(nameaddrlist[i].nsname);
+ nameaddrlist[i].nsname =
+ (char *)malloc((unsigned)strlen(servername)+1);
+ strcpy(nameaddrlist[i].nsname, servername);
+ return;
+ }
+ }
+ /* we have to add this one to our cache */
+
+ nameaddrlist[firstNA].nsname =
+ (char *)malloc((unsigned)strlen(servername)+1);
+ strcpy(nameaddrlist[firstNA].nsname, servername);
+ bcopy((char *)serveraddr,
+ (char *)&(nameaddrlist[firstNA].ns_addr),
+ INADDRSZ);
+
+ dprintf(2, (ddt, "store_name_addr:added entry #:%d n:%s a:[%s]\n",
+ firstNA, nameaddrlist[firstNA].nsname,
+ inet_ntoa(nameaddrlist[firstNA].ns_addr)));
+
+ firstNA = (firstNA+1) % MAXNAMECACHE;
+ if (firstNA == lastNA) {
+ free(nameaddrlist[firstNA].nsname);
+ nameaddrlist[firstNA].nsname = 0;
+ lastNA = (lastNA+1) % MAXNAMECACHE;
+ }
+ return;
+}
+
+/*
+ * Decode the resource record 'rrp' and validate the RR.
+ * Borrows code almost entirely from doupdate(). is a rather
+ * non-invasive routine since it just goes thru the same motions
+ * as doupdate but just marks the array validatelist entry as
+ * the return code from validate(). This is later used in doupdate
+ * to cache/not cache the entry. also used in update_msg() to
+ * delete/keep the record from the outgoing message.
+ */
+int
+dovalidate(msg, msglen, rrp, zone, flags, server, VCode)
+ u_char *msg, *rrp;
+ int msglen, zone, flags;
+ struct sockaddr_in *server;
+ int *VCode;
+{
+ register u_char *cp;
+ register int n;
+ int class, type, dlen, n1;
+ u_int32_t ttl;
+ char dname[MAXDNAME];
+ u_char *cp1;
+ u_char data[BUFSIZ];
+ register HEADER *hp = (HEADER *) msg;
+
+ dprintf(2, (ddt, "dovalidate(zone %d, flags %x)\n",
+ zone, flags));
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+
+ cp = rrp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+ dprintf(2, (ddt, "dovalidate: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * 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:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ 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:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = data;
+ n = strlen((char *)data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)data, sizeof data);
+ if (n < 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 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *)cp1) + 1;
+ if (type == T_SOA) {
+ bcopy((char *)cp, (char *)cp1, n = 5 * INT32SZ);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof(data) - INT16SZ);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return(-1);
+ }
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *)cp1) + 1;
+ /* compute size of data */
+ n = cp1 - data;
+ cp1 = data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(2, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ hp->rcode = NOCHANGE; /* XXX - FORMERR ??? */
+ return(-1);
+ }
+
+ *VCode = validate(dname, server, type, class,(char *)cp1, n
+#ifdef NCACHE
+ ,NOERROR
+#endif
+ );
+ if (*VCode == INVALID) {
+ dprintf(2, (ddt,
+ "validation failed d:%s, t:%d, c:%d\n",
+ dname, type, class));
+ } else {
+ dprintf(2, (ddt,
+ "validation succeeded d:%s, t:%d, c:%d\n",
+ dname, type, class));
+ }
+ return(cp -rrp);
+}
+
+#if 0
+/******************************************************************
+ * This manages a data structure that stores all RRs that we were
+ * unable to validate. Am not sure exactly what purpose this might
+ * serve but until such time as we are sure it will not help, let
+ * me do it anyway.
+ *****************************************************************/
+static void
+stick_in_queue(dname, type, class, data)
+ char *dname;
+ int type;
+ int class;
+ char *data;
+{
+ struct timeval tp;
+ struct _TIMEZONE tzp;
+ TO_Validate *tempVQ;
+ u_long leasttime;
+
+ if (validateQ == NULL) {
+ validateQ = (TO_Validate *)malloc(sizeof(TO_Validate));
+ validateQ->type = type;
+ validateQ->class = class;
+ validateQ->dname = malloc((unsigned)strlen(dname)+1);
+ strcpy(validateQ->dname, dname);
+ validateQ->data = malloc((unsigned)strlen(data)+1);
+ strcpy(validateQ->data, data);
+ gettimeofday(&tp, &tzp);
+ validateQ->time = tp.tv_sec;
+ VQcount = 1;
+ validateQ->next = validateQ->prev = NULL;
+ currentVQ = validateQ;
+ return;
+ }
+ if (VQcount < MAXVQ) {
+ tempVQ =(TO_Validate *)malloc(sizeof(TO_Validate));
+ tempVQ->type = type;
+ tempVQ->class = class;
+ tempVQ->dname = malloc((unsigned)strlen(dname)+1);
+ strcpy(tempVQ->dname, dname);
+ tempVQ->data = malloc((unsigned)strlen(data)+1);
+ strcpy(tempVQ->data, data);
+ gettimeofday(&tp,&tzp);
+ tempVQ->time = tp.tv_sec;
+ tempVQ->next = currentVQ->next;
+ tempVQ->prev = currentVQ;
+ if (currentVQ->next != NULL)
+ currentVQ->next->prev = tempVQ;
+ currentVQ->next = tempVQ;
+ currentVQ = tempVQ;
+ VQcount++;
+ return;
+ }
+ gettimeofday(&tp, &tzp);
+ leasttime = validateQ->time;
+ currentVQ = validateQ;
+ for (tempVQ = validateQ; tempVQ != NULL; tempVQ = tempVQ->next) {
+ if (tp.tv_sec >= tempVQ->time +VQEXPIRY) {
+ tempVQ->type = type;
+ tempVQ->class = class;
+ strcpy(tempVQ->dname, dname);
+ strcpy(tempVQ->data, data);
+ tempVQ->time = tp.tv_sec;
+ currentVQ = tempVQ;
+ return;
+ }
+ if (tempVQ->time < leasttime) {
+ leasttime = tempVQ->time;
+ currentVQ = tempVQ;
+ }
+ }
+ currentVQ->type = type;
+ currentVQ->class = class;
+ strcpy(currentVQ->dname, dname);
+ strcpy(currentVQ->data, data);
+ currentVQ->time = tp.tv_sec;
+ return;
+}
+#endif
+
+/* removes any INVALID RR's from the msg being returned, updates msglen to
+ * reflect the new message length.
+ */
+int
+update_msg(msg, msglen, Vlist, c)
+ u_char *msg;
+ int *msglen;
+ int Vlist[];
+ int c;
+{
+ register HEADER *hp;
+ register u_char *cp;
+ int i;
+ int n = 0;
+ u_char *tempcp, *newcp;
+ int *RRlen;
+ int qlen; /* the length of the query section*/
+ u_int16_t rdlength;
+ u_int16_t ancount, nscount;
+ u_int16_t new_ancount, new_nscount, new_arcount;
+ char dname[MAXDNAME], qname[MAXDNAME];
+ u_char data[MAXDNAME];
+ u_char **dpp;
+ u_char *dnptrs[40];
+ u_char **edp = dnptrs + sizeof(dnptrs)/sizeof(dnptrs[0]);
+ u_char *eom = msg + *msglen;
+ int n_new;
+ int rembuflen, newlen;
+ u_char *newmsg;
+ u_int16_t type, class, dlen;
+ u_int32_t ttl;
+ int inv = 0;
+
+#ifdef DEBUG
+ if (debug) {
+ fprintf(ddt, "update_msg: msglen:%d, c:%d\n", *msglen, c);
+ if (debug >= 10)
+ fp_query(msg, ddt);
+ }
+#endif
+ /* just making sure we do not do all the work for nothing */
+ for (i=0; i<c; i++) {
+ if (Vlist[i] == INVALID) {
+ inv = 1;
+ break;
+ }
+ }
+ if (inv != 1) {
+ /* no invalid records, go about your job */
+ return (0);
+ }
+
+ dprintf(2, (ddt, "update_msg: NEEDS updating:\n"));
+
+ RRlen = (int *)malloc((unsigned)c*sizeof(int));
+ hp = (HEADER *)msg;
+ new_ancount = ancount = ntohs(hp->ancount);
+ new_nscount = nscount = ntohs(hp->nscount);
+ new_arcount = ntohs(hp->arcount);
+
+ cp = msg + HFIXEDSZ;
+ newlen = HFIXEDSZ;
+ /* skip the query section */
+ qlen = dn_expand(msg, eom, cp, qname, sizeof qname);
+ if (qlen <= 0) {
+ dprintf(2, (ddt, "dn_skipname() failed, bad record\n"));
+ goto badend;
+ }
+ cp +=qlen;
+ GETSHORT(type,cp);
+ GETSHORT(class,cp);
+ qlen += 2 * INT16SZ;
+ newlen += qlen;
+
+ for (i = 0; i < c; i++) {
+ if (Vlist[i] == INVALID) {
+ if (i < ancount)
+ new_ancount--;
+ else if (i < ancount+nscount)
+ new_nscount--;
+ else
+ new_arcount--;
+ }
+
+ RRlen[i] = dn_skipname(cp, msg + *msglen);
+ if (RRlen[i] <= 0) {
+ dprintf(2, (ddt,
+ "dn_skipname() failed, bad record\n"));
+ goto badend;
+ }
+ RRlen[i] += 2 * INT16SZ + INT32SZ;
+ /*type+class+TTL*/
+ cp += RRlen[i];
+ GETSHORT(rdlength, cp);
+ RRlen[i] += INT16SZ; /*rdlength*/
+ RRlen[i] += rdlength; /*rdata field*/
+ dprintf(3, (ddt, "RRlen[%d]=%d\n", i, RRlen[i]));
+ if (Vlist[i] != INVALID)
+ newlen += RRlen[i];
+ cp += rdlength; /*increment pointer to next RR*/
+ }
+ hp->ancount = htons(new_ancount);
+ hp->nscount = htons(new_nscount);
+ hp->arcount = htons(new_arcount);
+ /* get new buffer */
+ dprintf(3, (ddt,
+ "newlen:%d, if no RR is INVALID == msglen\n", newlen));
+ newmsg = (u_char *)calloc(1,newlen + MAXDNAME);
+ if(newmsg == NULL)
+ goto badend;
+ dpp = dnptrs;
+ *dpp++ = newmsg;
+ *dpp = NULL;
+ /* bcopy the header, with all the length fields correctly put in */
+ bcopy((char *)msg, (char*)newmsg, HFIXEDSZ); /*header copied */
+ newcp = newmsg +HFIXEDSZ; /*need a pointer in the new buffer */
+ rembuflen = newlen +MAXDNAME - HFIXEDSZ; /*buflen we can workin*/
+ newlen = HFIXEDSZ; /* this will now contain the length of msg */
+ n_new = dn_comp(qname, newcp, rembuflen, dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ PUTSHORT(type, newcp);
+ PUTSHORT(class, newcp); /*query section complete*/
+ newlen += (n_new+2*INT16SZ);
+ rembuflen -= (n_new+2*INT16SZ);
+ /* have to decode and copy every Valid RR from here */
+
+ cp = msg +HFIXEDSZ +qlen; /*skip header and query section*/
+ for (i = 0; i < c; i++) {
+ if (Vlist[i] == INVALID) {
+ /* go to next RR if this one is not INVALID */
+ cp += RRlen[i];
+ continue;
+ }
+ /* we have a valid record, must put it in the newmsg */
+ n = dn_expand(msg, eom, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ n_new = dn_comp(dname, newcp, rembuflen, dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ cp += n;
+ newcp += n_new;
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting name\n",
+ cp, newcp));
+ GETSHORT(type, cp);
+ PUTSHORT(type, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting type\n",
+ cp, newcp));
+ GETSHORT(class, cp);
+ PUTSHORT(class, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting class\n",
+ cp, newcp));
+ GETLONG(ttl, cp);
+ PUTLONG(ttl, newcp);
+ dprintf(5, (ddt,
+ "cp:0x%x newcp:0x%x after getting ttl\n",
+ cp, newcp));
+ /* this will probably be modified for newmsg,
+ * will put this in later, after compression
+ */
+ GETSHORT(dlen, cp);
+ newlen += (n_new+3*INT16SZ + INT32SZ);
+ rembuflen -= (n_new+3*INT16SZ+ INT32SZ);
+ tempcp = newcp;
+ newcp += INT16SZ; /*advance to rdata field*/
+ dprintf(5, (ddt, "tempcp:0x%x newcp:0x%x\n",
+ tempcp, newcp));
+ dprintf(3, (ddt,
+ "update_msg: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /* read off the data section */
+ switch (type) {
+ case T_A:
+ case T_WKS:
+ case T_HINFO:
+ case T_UINFO:
+ case T_UID:
+ case T_GID:
+ case T_TXT:
+ case T_X25:
+ case T_ISDN:
+#ifdef ALLOW_T_UNSPEC
+ case T_UNSPEC:
+#endif
+ n = dlen;
+ PUTSHORT(n, tempcp); /*time to put in the dlen*/
+ bcopy(cp, newcp,n); /*done here*/
+ cp +=n;
+ newcp +=n;
+ newlen += n;
+ rembuflen -= n;
+ dprintf(3, (ddt, "\tcp:0x%x newcp:0x%x dlen:%d\n",
+ cp, newcp, dlen));
+ break;
+
+ case T_CNAME:
+ case T_MB:
+ case T_MG:
+ case T_MR:
+ case T_NS:
+ case T_PTR:
+ /*read off name from data section */
+ n = dn_expand(msg, eom, cp,
+ (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n; /*advance pointer*/
+ /* fill in new packet */
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ PUTSHORT(n_new,tempcp); /*put in dlen field*/
+ newcp += n_new; /*advance new pointer*/
+ newlen += n_new;
+ rembuflen -= n_new;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ newlen += n_new;
+ rembuflen -= n_new;
+ dlen = n_new;
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ newcp += n_new;
+ newlen += n_new;
+ rembuflen -= n_new;
+ dlen += n_new;
+ if (type == T_SOA) {
+ bcopy(cp, newcp, n = 5*INT32SZ);
+ cp += n;
+ newcp += n;
+ newlen +=n;
+ rembuflen -= n;
+ dlen +=n;
+ }
+ PUTSHORT(dlen, tempcp);
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy(cp,newcp,INT16SZ);
+ cp += INT16SZ;
+ newcp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, eom, cp, (char *)data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ goto badend;
+ }
+ cp += n;
+ n_new = dn_comp((char *)data, newcp, rembuflen,
+ dnptrs, edp);
+ if (n_new < 0)
+ goto badend;
+ PUTSHORT(n_new+INT16SZ, tempcp);
+ newcp += n_new;
+ newlen += n_new+INT16SZ;
+ rembuflen -= n_new+INT16SZ;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ goto badend;
+ }
+ dprintf(2, (ddt,
+ "newlen:%d, i:%d newcp:0x%x cp:0x%x\n\n",
+ newlen, i, newcp, cp));
+ }
+ bcopy(newmsg, msg, newlen);
+ n = *msglen - newlen;
+ if (n < 0) {
+ dprintf(2, (ddt,
+ "update_msg():newmsg longer than old: n:%d o:%d ???\n",
+ newlen, *msglen));
+ }
+ *msglen = newlen;
+ free((char *)newmsg);
+
+#ifdef DEBUG
+ if (debug >= 10)
+ fp_query(msg, ddt);
+#endif
+ free((char *)RRlen);
+ return(n);
+badend:
+ dprintf(2, (ddt, "encountered problems: UPDATE_MSG\n"));
+ free((char *)RRlen);
+ return(-1);
+}
+
+#endif /*VALIDATE*/
diff --git a/usr.sbin/named/options.h b/usr.sbin/named/options.h
new file mode 100644
index 0000000..8461389
--- /dev/null
+++ b/usr.sbin/named/options.h
@@ -0,0 +1,160 @@
+/* options.h - specify the conditionally-compiled features
+ * vix 28mar92 [moved out of the Makefile because they were getting too big]
+ *
+ * $Id: options.h,v 4.9.1.16 1994/07/22 08:42:30 vixie Exp $
+ */
+
+/*
+ * ++Copyright++
+ * -
+ * Copyright (c)
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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--
+ */
+
+/* Key:
+ * ucb = U C Berkeley 4.8.3 release
+ * vix = Paul Vixie of Digital
+ * del = Don Lewis of Harris
+ * mcsun = Piet Beertema of EUNet
+ * asp = Andrew Partan of UUNet
+ * pma = Paul Albitz of Hewlett Packard
+ * bb = Bryan Beecher of UMich
+ * mpa = Mark Andrews of CSIRO - DMS
+ * rossc = Ross Cartlidge of The Univeritsy of Sydney
+ * mtr = Marshall Rose of TPC.INT
+ */
+
+#define DEBUG /* enable -d flag and SIGUSR[12] support (ucb) */
+/*#define ALLOW_T_UNSPEC /* enable the "unspec" RR type for old athena (ucb) */
+#define INVQ /* enable inverse queries (nslookup) (ucb/vix) */
+/*#define DSTORAGE /* debug malloc overruns using storage.o (ucb/vix) */
+/*#define DMALLOC /* trace malloc orphans using dmalloc.o (vix) */
+#define XFRNETS /* enable "xfrnets" command in named.boot (vix) */
+#define PID_FIX /* be careful about overwriting named.pid file (del) */
+#define FWD_LOOP /* try to break out of forwarding loops (del) */
+#define NO_GLUE /* don't accept or send out-of-zone glue (del) */
+#define BOGUSNS /* detect bogus nameservers (mcsun) */
+#define QRYLOG /* enable SIGWINCH for query logging (bb) */
+/*#define YPKLUDGE /* deal effectively with broken "ypserv -i" (mcsun) */
+#define TRACEROOT /* trace bogus root servers and ignore them (pma,bb) */
+/*#define LOCALDOM /* permit "domain" directive in named.boot (ucb) */
+#define FORCED_RELOAD /* refresh secondary zones on SIGHUP (pma) */
+#define SLAVE_FORWARD /* use sensible timeouts on slave forwarders (pma) */
+#define WANT_PIDFILE /* if you want the named.pid file (ucb/arc) */
+#define DOTTED_SERIAL /* if you want to be able to specify dotted serial#s */
+/*#define SENSIBLE_DOTS /* if you want dotted serial#s to make numeric sense */
+#define NCACHE /* negative caching (anant@isi.edu) */
+#define VALIDATE /* validation procedure (anant@isi.edu) */
+/*#define SHORT_FNAMES /* file names used in named-xfer need to be short */
+#define RESOLVSORT /* allow sorting of addresses in gethostbyname (mpa) */
+#define STUBS /* allow transfers of NS only for a zone (mpa) (EXP) */
+/*#define SUNSECURITY /* obscure fix for sunos (see below) */
+#define LOGFAC LOG_DAEMON /* what syslog facility should named use? */
+/*#define SECURE_ZONES /* if you want to inhibit world access to zone(s) */
+#define ROUND_ROBIN /* rotate databuf list after each access (mtr) */
+#define ADDAUTH /* return NS and glue w/ authorative answers (mpa) */
+#define RFC1535 /* use RFC 1535 default for "search" list (vix) */
+#define GEN_AXFR /* distinct zones within each class */
+#define DATUMREFCNT /* use reference counts on datums (mpa) */
+#define LAME_DELEGATION /* lame delegations (original-del,reworked-bb&del)*/
+#define LAME_LOGGING LOG_WARNING /* log lame delegations, set log level */
+#define GETSER_LOGGING LOG_INFO /* log errors/timeouts getting serial number */
+/*#define RETURNSOA /* good code that the world isn't ready for yet */
+#define CLEANCACHE /* useful and necessary in the face of NCACHE */
+#define STATS /* keep nameserver statistics; uses more memory */
+/*#define RENICE /* named-xfer should run at normal priority */
+
+/*--------------------------------------------*
+ * no user-servicable parts beyond this point *
+ *--------------------------------------------*/
+
+/* if DSTORAGE is defined, we need to disable DMALLOC and remap
+ * malloc and free to storage.o's exported names. storage.o also
+ * includes a calloc and a realloc, but once we drag in its malloc
+ * and free we'll get the others automatically and so will never
+ * pull in those routines from libc.a.
+ */
+#ifdef DSTORAGE
+# ifdef DMALLOC
+# undef DMALLOC
+# endif /*DMALLOC*/
+# define malloc rt_malloc
+# define free rt_free
+#endif /*DSTORAGE*/
+
+/* if DMALLOC is defined, grab the header file which will remap
+ * all the malloc-style names to those exported by dmalloc.o. note
+ * that DMALLOC also changes the function signatures of several
+ * functions in private named source modules, and that this file
+ * (options.h) must be included before any other private *.h files
+ * since those *.h files have some conditional remapping to do.
+ */
+#ifdef DMALLOC
+# include "dmalloc.h"
+#endif
+
+/* systems with killall(1M) don't need this
+ */
+#ifdef __sgi
+# ifdef WANT_PIDFILE
+# undef WANT_PIDFILE
+# endif
+#endif
+
+#if defined(SUNOS4) || (defined(sun) && defined(SYSV))
+# ifndef SUNSECURITY
+# define SUNSECURITY /* mandatory on suns and rlogin etc. depend on this */
+# endif
+#endif
+
+#ifdef LAME_LOGGING
+# define LAME_DELEGATION
+#endif
diff --git a/usr.sbin/named/pathnames.h b/usr.sbin/named/pathnames.h
new file mode 100644
index 0000000..bcbe642
--- /dev/null
+++ b/usr.sbin/named/pathnames.h
@@ -0,0 +1,122 @@
+/*
+ * @(#)pathnames.h 5.4 (Berkeley) 6/1/90
+ * $Id: pathnames.h,v 4.9.1.5 1994/04/09 03:43:17 vixie Exp $
+ */
+
+/*
+ * ++Copyright++ 1989
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#ifdef _PATH_XFER
+# define _PATH_XFER_PREDEFINED /* probably from Makefile */
+#endif
+
+#if defined (__sgi) && !defined(_SYSTYPE_SVR4) && !defined(__SYSTYPE_SVR4)
+#define _PATH_BOOT "/usr/etc/named.d/named.boot"
+#else
+#define _PATH_BOOT "/etc/named.boot"
+#endif
+
+#if defined(BSD) && BSD >= 198810
+
+#include <paths.h>
+#ifndef _PATH_XFER
+# define _PATH_XFER "/usr/libexec/named-xfer"
+#endif
+#define _PATH_DEBUG "/var/tmp/named.run"
+#define _PATH_DUMPFILE "/var/tmp/named_dump.db"
+#ifndef _PATH_PIDFILE
+# define _PATH_PIDFILE "/var/run/named.pid"
+#endif
+#define _PATH_STATS "/var/tmp/named.stats"
+#define _PATH_XFERTRACE "/var/tmp/xfer.trace"
+#define _PATH_XFERDDT "/var/tmp/xfer.ddt"
+#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"
+#ifndef _PATH_XFER
+# define _PATH_XFER "/etc/named-xfer"
+#endif
+#define _PATH_DEBUG "/usr/tmp/named.run"
+#define _PATH_DUMPFILE "/usr/tmp/named_dump.db"
+#ifndef _PATH_PIDFILE
+# define _PATH_PIDFILE "/etc/named.pid"
+#endif
+#define _PATH_STATS "/usr/tmp/named.stats"
+#define _PATH_XFERTRACE "/usr/tmp/xfer.trace"
+#define _PATH_XFERDDT "/usr/tmp/xfer.ddt"
+#define _PATH_TMPXFER "/usr/tmp/xfer.ddt.XXXXXX"
+#define _PATH_TMPDIR "/usr/tmp"
+#endif /* BSD */
+
+#ifndef _PATH_XFER_PREDEFINED
+# if defined(__sgi) || defined(NeXT) || defined(__ultrix)
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/etc/named-xfer"
+# endif
+# if defined(__osf__)
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/sbin/named-xfer"
+# endif
+# ifdef sun
+# undef _PATH_XFER
+# define _PATH_XFER "/usr/etc/in.named-xfer"
+# endif
+#else
+# undef _PATH_XFER_PREDEFINED
+#endif /*_PATH_XFER_PREDEFINED*/
diff --git a/usr.sbin/named/portability.h b/usr.sbin/named/portability.h
new file mode 100644
index 0000000..1aeb233
--- /dev/null
+++ b/usr.sbin/named/portability.h
@@ -0,0 +1,456 @@
+/* defs.h - include or define things that aren't present on all systems
+ * vixie@decwrl 26dec92 [new]
+ *
+ * $Id: portability.h,v 4.9.1.24 1994/07/22 08:42:30 vixie Exp $
+ */
+
+/*
+ * ++Copyright++
+ * -
+ * Copyright (c)
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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--
+ */
+
+/* XXX: this file has become a hopeless morass, and will be redone someday. */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#ifndef TIME_H_INCLUDED
+# include <sys/time.h>
+# define TIME_H_INCLUDED
+#endif
+
+#if defined(__convex__)
+# if !defined(_POSIX_SOURCE)
+# define _POSIX_SOURCE
+# endif
+# define USE_UTIME
+# define NEED_PUTENV
+#endif
+
+#if defined(_CRAY)
+# if !defined(_POSIX_SOURCE)
+# define _POSIX_SOURCE
+# endif
+# define writev(a,b,c) __writev(a,b,c)
+# define setitimer(a,b,c) __setitimer(a,b,c)
+#endif
+
+/* SCO UNIX defines only this unique symbol, apparently. */
+#if defined(M_UNIX)
+/* XXX - why is this POSIX_SOURCE instead of _POSIX_SOURCE? */
+# undef POSIX_SOURCE
+# define POSIX_SIGNALS
+# define HAVE_FCHMOD 0
+# define writev(a,b,c) __writev(a,b,c)
+# define ftruncate(a,b) __ftruncate(a,b)
+#endif
+
+#ifdef NeXT
+# define NEED_PUTENV
+# define NEED_SETENV
+#endif
+
+#if defined(__sgi)
+# define BSD 43
+# define vfork fork
+#endif
+
+#if defined(SUNOS4)
+# define BSD 43
+#endif
+
+#if defined(_POSIX_SOURCE) || defined(__sgi) || defined(ultrix) || \
+ defined(__hpux) || (defined(BSD) && (BSD >= 199103)) || \
+ (defined(sun) && defined(SYSV))
+# define USE_POSIX
+#endif
+
+#if defined(ultrix) && !defined(BSD)
+# define BSD 42
+#endif
+
+#if defined(host_mips) && defined(SYSTYPE_BSD43)
+# define RISCOS_BSD
+#endif
+
+#if defined(SVR4) && !defined(SYSV)
+# define SYSV
+#endif
+
+#if defined(SYSV) || defined(ultrix) || (defined(BSD) && BSD >= 199306)
+# define USE_UTIME
+#endif
+
+#if defined(BSD) && BSD >= 199006 && !defined(i386) && !defined(RISCOS_BSD)
+# define HAVE_DAEMON
+#endif
+
+#if defined(__hpux)
+# if defined(__STDC__)
+# define select(a,b,c,d,e) select(a, (int *)b, (int *)c, (int *)d, e)
+# define ctime(x) ctime((const time_t *)x)
+# endif /*__STDC__*/
+# ifndef SYSV
+# define USE_UTIME
+# define setlinebuf(x) setvbuf(x, NULL, _IOLBF, BUFSIZ)
+# define SIGWINCH SIGWINDOW
+# endif /*SYSV*/
+#endif /*__hpux*/
+
+#if defined(_SEQUENT_)
+# include <netinet/in_systm.h>
+# define USE_UTIME
+# define USE_POSIX
+# define NEED_GETTIMEOFDAY
+# define _TIMEZONE timezoneBSD
+struct timezoneBSD {
+ int tz_minuteswest;
+ int tz_dsttime;
+};
+#endif
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+#ifndef _TIMEZONE
+# define _TIMEZONE timezone
+#endif
+
+#if defined(USE_POSIX)
+# include <stdlib.h>
+# include <unistd.h>
+# include <limits.h>
+
+#else
+
+# define NEED_STRTOUL
+
+# define STDIN_FILENO 0
+# define STDOUT_FILENO 1
+# define STDERR_FILENO 2
+# ifndef NeXT
+extern char *getenv __P((char *));
+# else
+extern char *getenv __P((const char *));
+# endif
+extern int errno;
+
+# if !defined(DMALLOC) && !defined(NeXT)
+extern char *malloc(), *realloc(), *calloc();
+# if defined(sun)
+extern int free();
+# else
+extern void free();
+# endif
+# endif
+
+extern int getdtablesize __P((void));
+# ifdef SHORT_FNAMES
+extern long pathconf __P((const char *path, int name));
+# endif
+
+#endif /*USE_POSIX*/
+
+#ifndef UINT_MAX
+# ifdef __STDC__
+# define UINT_MAX 4294967295u /* max value of an "u_int" */
+# else
+# define UINT_MAX ((unsigned)4294967295) /* max value of an "u_int" */
+# endif
+# define ULONG_MAX UINT_MAX /* max decimal value of a "u_long" */
+#endif
+
+#ifndef INT_MAX
+# define INT_MAX 2147483647 /* max decimal value of an "int" */
+#endif
+
+#ifndef IN_LOOPBACKNET
+# define IN_LOOPBACKNET 127
+#endif
+
+#ifndef INADDR_NONE
+# define INADDR_NONE 0xffffffff
+#endif
+
+#if defined(apollo)
+ /* Defined in /usr/include/netinet/in.h but doesn't work */
+#undef IP_OPTIONS
+#endif
+
+#if !defined(__STDC__) && !defined(const)
+# define const /*constant*/
+#endif
+
+#if !defined(__convex__) && (!defined(BSD) || (BSD < 199103))
+int strcasecmp __P((const char *, const char *));
+#endif
+
+/* is USE_POSIX the right thing to use here? */
+#if (!defined(BSD) || (BSD <= 43)) && \
+ !defined(NeXT) && \
+ !defined(__convex__) && \
+ !defined(USE_POSIX)
+extern void syslog();
+extern char *ctime __P((const time_t *clock));
+extern int close(), setitimer(), recv(), sendto(), sigsetmask(),
+ atoi(), getpid(), fork(), read(), ioctl(),
+ setsockopt(), socket(), bind();
+#endif
+
+#if !defined(bcopy) /* some machines have their own macros for this */
+# if defined(USE_POSIX) || \
+ (defined(__STDC__) && !defined(sun) && !defined(sequent))
+/* use ANSI C3.159-1989 (``ANSI C'') functions if possible;
+ * ideally we would change the code to use them and then
+ * define them in terms of bcopy et al if !defined(__STDC__)
+ * but that's more work.
+ */
+# define bcopy(a,b,c) memmove(b,a,c)
+# define bzero(a,b) memset(a,0,b)
+# define bcmp(a,b,c) memcmp(a,b,c)
+# else
+extern void bcopy();
+extern void bzero();
+extern int bcmp();
+# endif /* BSD */
+#endif /* bcopy */
+
+#if (!defined(BSD) || (BSD < 43) || defined(RISCOS_BSD)) \
+ && !defined(USE_POSIX) && !defined(apollo) && !defined(sequent) \
+ && !defined(M_UNIX)
+# define NEED_STRERROR
+# define NEED_PUTENV
+#endif
+
+#if defined(SUNOS4)
+# define NEED_STRERROR
+#endif
+
+#if (!defined(BSD) || (BSD < 43))
+# define NEED_MKSTEMP
+# if !defined(ultrix) && !defined(apollo)
+# define NEED_STRCASECMP
+# define NEED_MKTEMP
+# define NEED_STRPBRK
+# endif
+#endif
+
+#if defined(USE_POSIX)
+# define POSIX_SIGNALS
+#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) || defined(NeXT) || defined(__osf__) || defined(sun) \
+ || defined(ultrix) || defined(apollo) || defined(POSIX_SIGNALS)
+# 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
+
+#if !defined(ntohl) && !defined(htonl) && defined(BSD) && (BSD <= 43)
+/* if these aren't null macros in netinet/in.h, extern them here. */
+extern u_short htons(), ntohs();
+extern u_long htonl(), ntohl();
+#endif
+
+#if defined(USE_POSIX) && !defined(sun) && !defined(__sgi) \
+ && !defined(__convex__) && !defined(ultrix)
+# define PORT_NONBLOCK O_NONBLOCK
+# define PORT_WOULDBLK EAGAIN
+#else
+# define PORT_NONBLOCK O_NDELAY
+# define PORT_WOULDBLK EWOULDBLOCK
+#endif
+
+#if defined(USE_POSIX)
+# define USE_SETSID
+#endif
+
+#if defined(USE_POSIX) || !defined(SYSV)
+#define USE_WAITPID
+#endif
+
+#if !defined(USE_POSIX)
+#define waitpid(x,y,z) (wait3(y,z,(struct rusage *)NULL))
+#endif
+
+#if defined(NeXT) || defined(_AIX)
+# undef WIFEXITED
+# undef WEXITSTATUS
+# undef WIFSIGNALED
+# undef WTERMSIG
+#endif /* NeXT */
+
+#if defined(sequent)
+#define WEXITSTATUS(x) ((x).w_retcode)
+#define WTERMSIG(x) ((x).w_termsig)
+#endif /* sequent */
+
+#if !defined(WIFEXITED)
+# define WIFEXITED(x) (!(x & 0200))
+#endif
+#if !defined(WEXITSTATUS)
+# define WEXITSTATUS(x) (x >> 8)
+#endif
+#if !defined(WIFSIGNALED)
+# define WIFSIGNALED(x) ((x & 0200) && ((x & 0200) != 0177))
+#endif
+#if !defined(WTERMSIG)
+# define WTERMSIG(x) (x & 0177)
+#endif
+
+#ifndef S_ISDIR
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFDIR
+# define S_IFDIR 0040000
+# endif
+# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISREG
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFREG
+# define S_IFREG 0100000
+# endif
+# define S_ISREG(m) ((m & S_IFMT) == S_IFREG)
+#endif
+
+#ifndef S_ISFIFO
+# ifndef S_IFMT
+# define S_IFMT 0170000
+# endif
+# ifndef S_IFIFO
+# define S_IFIFO 0010000
+# endif
+# define S_ISFIFO(m) ((m & S_IFMT) == S_IFIFO)
+#endif
+
+#if (defined(ultrix) || defined(__osf__)) && defined(NEED_STRTOUL)
+# undef NEED_STRTOUL
+#endif
+
+#if defined(ultrix) || defined(__osf__)
+# define MAYBE_HESIOD
+#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
+
+#ifndef MIN
+# define MIN(x, y) ((x > y) ?y :x)
+#endif
+#ifndef MAX
+# define MAX(x, y) ((x > y) ?x :y)
+#endif
+
+#if !defined(PATH_MAX)
+# if defined(_POSIX_PATH_MAX)
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# if defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+# endif
+# endif
+#endif
+
+/*
+ * Because Convex has true library function feof() which is
+ * patently wrong (it test bit _IOREAD) we need feof() as
+ * a macro.
+ */
+#if defined(__convex__) && !defined(feof)
+# define feof(p) ((p)->_flag&_IOEOF)
+#endif
+
+/*
+ * Assume that a system has fchmod() unless something above says otherwise.
+ */
+#if !defined(HAVE_FCHMOD)
+# define HAVE_FCHMOD 1
+#endif
+
+/*
+ * Prototype the functions we'll be supplying.
+ */
+#ifdef NEED_PUTENV
+extern int putenv __P((char *));
+#endif
+
+#ifdef NEED_GETTIMEOFDAY
+extern int gettimeofday __P((struct timeval *, struct _TIMEZONE *));
+#endif
diff --git a/usr.sbin/named/storage.c b/usr.sbin/named/storage.c
new file mode 100644
index 0000000..5f995cc
--- /dev/null
+++ b/usr.sbin/named/storage.c
@@ -0,0 +1,205 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#include <sys/param.h>
+#include <syslog.h>
+
+#ifdef DSTORAGE
+/*
+ * 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 1994/09/22 19:46:14 pst Exp $";
+#endif
+
+#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;
+
+ 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;
+{
+ 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);
+}
+
+#endif /*DSTORAGE*/
diff --git a/usr.sbin/named/tools/Makefile b/usr.sbin/named/tools/Makefile
new file mode 100644
index 0000000..4c6be85
--- /dev/null
+++ b/usr.sbin/named/tools/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 4.10 (Berkeley) 5/29/90
+
+SUBDIR= named.reload named.restart nsquery nstest
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/named/tools/named.reload/Makefile b/usr.sbin/named/tools/named.reload/Makefile
new file mode 100644
index 0000000..5ebc77f
--- /dev/null
+++ b/usr.sbin/named/tools/named.reload/Makefile
@@ -0,0 +1,18 @@
+# @(#)Makefile 5.1 (Berkeley) 5/28/90
+
+MAN8= named.reload.8
+CLEANFILES+=named.reload
+
+PIDDIR=/var/run
+INDOT=
+
+beforeinstall: named.reload
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
+ named.reload ${DESTDIR}${BINDIR}
+
+named.reload: named.reload.sh Makefile
+ sed -e "s|%PIDDIR%|${PIDDIR}|" \
+ < ${.CURDIR}/named.reload.sh > named.reload
+
+.include "${.CURDIR}/../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/tools/named.reload/named.reload.8 b/usr.sbin/named/tools/named.reload/named.reload.8
new file mode 100644
index 0000000..b838ea0
--- /dev/null
+++ b/usr.sbin/named/tools/named.reload/named.reload.8
@@ -0,0 +1,69 @@
+.\" ++Copyright++ 1987, 1993
+.\" -
+.\" 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.
+.\" -
+.\" 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 hostname.7 6.4 (Berkeley) 1/16/90
+.\"
+.TH @INDOT_U@NAMED.RELOAD @SYS_OPS_EXT_U@ "June 26, 1993"
+.UC 5
+.SH NAME
+@INDOT@named.reload \- cause the name server to synchronize its database
+.SH DESCRIPTION
+This command sends a \s-1SIGHUP\s+1 to the running name server. This
+signal is documented in
+.IR named (@SYS_OPS_EXT@).
+.SH BUGS
+Does not check to see if the name server is actually running, and could
+use a stale PID cache file which may result in the death of an unrelated
+process.
+.SH SEE ALSO
+@INDOT@named(@SYS_OPS_EXT@), @INDOT@named.restart(@SYS_OPS_EXT@)
diff --git a/usr.sbin/named/tools/named.reload/named.reload.sh b/usr.sbin/named/tools/named.reload/named.reload.sh
new file mode 100644
index 0000000..a25de1b
--- /dev/null
+++ b/usr.sbin/named/tools/named.reload/named.reload.sh
@@ -0,0 +1,6 @@
+#!/bin/sh -
+#
+# from named.reload 5.2 (Berkeley) 6/27/89
+# $Id: named.reload.sh,v 4.9.1.2 1993/09/08 00:01:17 vixie Exp $
+#
+kill -HUP `cat %PIDDIR%/named.pid`
diff --git a/usr.sbin/named/tools/named.restart/Makefile b/usr.sbin/named/tools/named.restart/Makefile
new file mode 100644
index 0000000..e5ffe0a
--- /dev/null
+++ b/usr.sbin/named/tools/named.restart/Makefile
@@ -0,0 +1,20 @@
+# @(#)Makefile 5.1 (Berkeley) 5/28/90
+
+MAN8= named.restart.8
+CLEANFILES+=named.restart
+
+PIDDIR=/var/run
+INDOT=
+
+beforeinstall: named.restart
+ install -c -o ${BINOWN} -g ${BINGRP} -m 555 \
+ named.restart ${DESTDIR}${BINDIR}
+
+named.restart: named.restart.sh Makefile
+ sed -e "s|%PIDDIR%|${PIDDIR}|" \
+ -e "s|%INDOT%|${INDOT}|" \
+ -e "s|%DESTSBIN%|${BINDIR}|" \
+ < ${.CURDIR}/named.restart.sh > named.restart
+
+.include "${.CURDIR}/../../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/named/tools/named.restart/named.restart.8 b/usr.sbin/named/tools/named.restart/named.restart.8
new file mode 100644
index 0000000..034bebd
--- /dev/null
+++ b/usr.sbin/named/tools/named.restart/named.restart.8
@@ -0,0 +1,73 @@
+.\" ++Copyright++ 1987, 1993
+.\" -
+.\" 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.
+.\" -
+.\" 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 hostname.7 6.4 (Berkeley) 1/16/90
+.\"
+.TH @INDOT_U@NAMED.RESTART @SYS_OPS_EXT_U@ "June 26, 1993"
+.UC 5
+.SH NAME
+@INDOT@named.restart \- stop and restart the name server
+.SH DESCRIPTION
+This command sends a \s-1SIGKILL\s+1 to the running name server and then
+starts a new one.
+.SH BUGS
+Does not check to see if the name server is actually running, and could
+use a stale PID cache file which may result in the death of an unrelated
+process.
+.PP
+Does not wait after killing the old server before starting a new one; since
+the server could take some time to die and the new one will experience a
+fatal error if the old one isn't gone by the time it starts, you can be left
+in a situation where you have no name server at all.
+.SH SEE ALSO
+@INDOT@named(@SYS_OPS_EXT@), @INDOT@named.reload(@SYS_OPS_EXT@)
diff --git a/usr.sbin/named/tools/named.restart/named.restart.sh b/usr.sbin/named/tools/named.restart/named.restart.sh
new file mode 100644
index 0000000..8a61ccca
--- /dev/null
+++ b/usr.sbin/named/tools/named.restart/named.restart.sh
@@ -0,0 +1,12 @@
+#!/bin/sh -
+#
+# from named.restart 5.4 (Berkeley) 6/27/89
+# $Id: named.restart.sh,v 4.9.1.5 1994/04/09 03:43:17 vixie Exp $
+#
+
+PATH=%DESTSBIN%:/bin:/usr/bin
+
+pid=`cat %PIDDIR%/named.pid`
+kill $pid
+sleep 5
+exec %INDOT%named
diff --git a/usr.sbin/named/tools/nsquery/Makefile b/usr.sbin/named/tools/nsquery/Makefile
new file mode 100644
index 0000000..5263aa1
--- /dev/null
+++ b/usr.sbin/named/tools/nsquery/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.1 (Berkeley) 5/28/90
+
+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 0000000..2a00de0
--- /dev/null
+++ b/usr.sbin/named/tools/nsquery/nsquery.c
@@ -0,0 +1,140 @@
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nsquery.c 4.8 (Berkeley) 6/1/90";
+static char rcsid[] = "$Id: nsquery.c,v 4.9.1.4 1994/06/11 22:05:07 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <string.h>
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ extern struct __res_state _res;
+ register struct hostent *hp;
+ register char *s;
+
+ res_init();
+
+ 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;
+#ifdef nsaddr /* struct __res_state includes nscount and nsaddr_list[] */
+ _res.nscount = 1;
+#endif
+ }
+
+ 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;
+
+ 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 0000000..e976d52
--- /dev/null
+++ b/usr.sbin/named/tools/nstest/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 5.1 (Berkeley) 5/28/90
+
+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 0000000..9104a8e
--- /dev/null
+++ b/usr.sbin/named/tools/nstest/nstest.c
@@ -0,0 +1,423 @@
+/*
+ * ++Copyright++ 1986
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1986 Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)nstest.c 4.15 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: nstest.c,v 4.9.1.6 1994/06/01 21:10:11 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <stdio.h>
+#include <resolv.h>
+
+char *progname;
+FILE *log;
+#define MAXDATA 256 /* really should get this from named/db.h */
+main(argc, argv)
+ char **argv;
+{
+ register char *cp;
+ register u_char *ucp;
+ struct hostent *hp;
+ u_short port = htons(NAMESERVER_PORT);
+ char buf[BUFSIZ];
+ u_char packet[PACKETSZ], answer[8*1024], OldRRData[MAXDATA];
+ struct rrec NewRR;
+ u_int32_t l;
+ 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 = inet_makeaddr(IN_LOOPBACKNET, 1);
+ _res.nsaddr.sin_port = port;
+ if (argc > 1) {
+ if (!inet_aton(argv[1],
+ (struct in_addr *)&_res.nsaddr.sin_addr))
+ usage();
+ }
+ if (argc > 2) {
+ log = fopen(argv[2],"w");
+ if (log == NULL) perror(argv[2]);
+ }
+ for (;;) {
+ printf("> ");
+ fflush(stdout);
+ if ((cp = fgets(buf, sizeof buf, stdin)) == NULL)
+ break;
+ switch (*cp++) {
+ case 'a':
+ n = res_mkquery(QUERY, cp, C_IN, T_A, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'A':
+ n = ntohl(inet_addr(cp));
+ putlong((u_int32_t)n, (u_char*)cp);
+ n = res_mkquery(IQUERY, "", C_IN, T_A, (u_char *)cp,
+ INT32SZ, NULL,
+ packet, sizeof(packet));
+ break;
+
+ case 'f':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UINFO, NULL,
+ 0, NULL, packet, sizeof packet);
+ break;
+
+ case 'F':
+ n = res_mkquery(QUERY, cp, C_IN, T_AFSDB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'g':
+ n = res_mkquery(QUERY, cp, C_ANY, T_GID, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'G':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_GID, (u_char *)cp,
+ sizeof(int), NULL, packet, sizeof packet);
+ break;
+
+ case 'c':
+ n = res_mkquery(QUERY, cp, C_IN, T_CNAME, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'h':
+ n = res_mkquery(QUERY, cp, C_IN, T_HINFO, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'm':
+ n = res_mkquery(QUERY, cp, C_IN, T_MX, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'M':
+ n = res_mkquery(QUERY, cp, C_IN, T_MAILB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'n':
+ n = res_mkquery(QUERY, cp, C_IN, T_NS, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'p':
+ n = res_mkquery(QUERY, cp, C_IN, T_PTR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 's':
+ n = res_mkquery(QUERY, cp, C_IN, T_SOA, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'T':
+ n = res_mkquery(QUERY, cp, C_IN, T_TXT, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'u':
+ n = res_mkquery(QUERY, cp, C_ANY, T_UID, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'U':
+ *(int *)cp = htonl(atoi(cp));
+ n = res_mkquery(IQUERY, "", C_ANY, T_UID, (u_char *)cp,
+ sizeof(int), NULL,
+ packet, sizeof packet);
+ break;
+
+ case 'x':
+ n = res_mkquery(QUERY, cp, C_IN, T_AXFR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'w':
+ n = res_mkquery(QUERY, cp, C_IN, T_WKS, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'b':
+ n = res_mkquery(QUERY, cp, C_IN, T_MB, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'B':
+ n = res_mkquery(QUERY, cp, C_IN, T_MG, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'i':
+ n = res_mkquery(QUERY, cp, C_IN, T_MINFO, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case 'r':
+ n = res_mkquery(QUERY, cp, C_IN, T_MR, NULL, 0,
+ NULL, packet, sizeof packet);
+ break;
+
+ case '*':
+ n = res_mkquery(QUERY, cp, C_IN, T_ANY, NULL, 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 = INT32SZ;
+ 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
+ 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("F{host} - query T_AFSDB\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/tree.c b/usr.sbin/named/tree.c
new file mode 100644
index 0000000..58607ea
--- /dev/null
+++ b/usr.sbin/named/tree.c
@@ -0,0 +1,570 @@
+/* tree - balanced binary tree library
+ *
+ * vix 05apr94 [removed vixie.h dependencies; cleaned up formatting, names]
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 23jun86 [added delete uar to add for replaced nodes]
+ * vix 20jun86 [added tree_delete per wirth a+ds (mod2 v.) p. 224]
+ * vix 06feb86 [added tree_mung()]
+ * vix 02feb86 [added tree balancing from wirth "a+ds=p" p. 220-221]
+ * vix 14dec85 [written]
+ */
+
+
+/* This program text was created by Paul Vixie using examples from the book:
+ * "Algorithms & Data Structures," Niklaus Wirth, Prentice-Hall, 1986, ISBN
+ * 0-13-022005-1. Any errors in the conversion from Modula-2 to C are Paul
+ * Vixie's.
+ *
+ * This code and associated documentation is hereby placed in the public
+ * domain, with the wish that my name and Prof. Wirth's not be removed
+ * from the source or documentation.
+ */
+
+
+#ifndef LINT
+static char RCSid[] = "$Id:";
+#endif
+
+
+/*#define DEBUG "tree"*/
+
+
+#include <stdio.h>
+#ifndef _PATH_XFER
+# include <stdlib.h>
+#else
+# include "../conf/portability.h"
+#endif
+#include "tree.h"
+
+
+#ifdef DEBUG
+static int debugDepth = 0;
+static char *debugFuncs[256];
+# define ENTER(proc) { \
+ debugFuncs[debugDepth] = proc; \
+ fprintf(stderr, "ENTER(%d:%s.%s)\n", \
+ debugDepth, DEBUG,
+ debugFuncs[debugDepth]); \
+ debugDepth++; \
+ }
+# define RET(value) { \
+ debugDepth--; \
+ fprintf(stderr, "RET(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return (value); \
+ }
+# define RETV { \
+ debugDepth--; \
+ fprintf(stderr, "RETV(%d:%s.%s)\n", \
+ debugDepth, DEBUG, \
+ debugFuncs[debugDepth]); \
+ return; \
+ }
+# define MSG(msg) fprintf(stderr, "MSG(%s)\n", msg);
+#else
+# define ENTER(proc) ;
+# define RET(value) return (value);
+# define RETV return;
+# define MSG(msg) ;
+#endif
+
+
+#ifndef TRUE
+# define TRUE 1
+# define FALSE 0
+#endif
+
+
+static tree * sprout __P( (tree **, tree_t, int *, int (*)(), void (*)()) );
+static int delete __P( (tree **, int (*)(), tree_t, void (*)(),
+ int *, int *) );
+static void del __P( (tree **, int *, tree **, void (*)(), int *) );
+static void bal_L __P( (tree **, int *) );
+static void bal_R __P( (tree **, int *) );
+
+
+void
+tree_init(ppr_tree)
+ tree **ppr_tree;
+{
+ ENTER("tree_init")
+ *ppr_tree = NULL;
+ RETV
+}
+
+
+tree_t
+tree_srch(ppr_tree, pfi_compare, p_user)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+{
+ register int i_comp;
+
+ ENTER("tree_srch")
+
+ if (*ppr_tree) {
+ i_comp = (*pfi_compare)(p_user, (**ppr_tree).data);
+
+ if (i_comp > 0)
+ RET(tree_srch(&(**ppr_tree).right,
+ pfi_compare,
+ p_user))
+
+ if (i_comp < 0)
+ RET(tree_srch(&(**ppr_tree).left,
+ pfi_compare,
+ p_user))
+
+ /* not higher, not lower... this must be the one.
+ */
+ RET((**ppr_tree).data)
+ }
+
+ /* grounded. NOT found.
+ */
+ RET(NULL)
+}
+
+
+tree_t
+tree_add(ppr_tree, pfi_compare, p_user, pfv_uar)
+ tree **ppr_tree;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE;
+
+ ENTER("tree_add")
+ if (!sprout(ppr_tree, p_user, &i_balance, pfi_compare, pfv_uar))
+ RET(NULL)
+ RET(p_user)
+}
+
+
+int
+tree_delete(ppr_p, pfi_compare, p_user, pfv_uar)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+{
+ int i_balance = FALSE,
+ i_uar_called = FALSE;
+
+ ENTER("tree_delete");
+ RET(delete(ppr_p, pfi_compare, p_user, pfv_uar,
+ &i_balance, &i_uar_called))
+}
+
+
+int
+tree_trav(ppr_tree, pfi_uar)
+ tree **ppr_tree;
+ int (*pfi_uar)();
+{
+ ENTER("tree_trav")
+
+ if (!*ppr_tree)
+ RET(TRUE)
+
+ if (!tree_trav(&(**ppr_tree).left, pfi_uar))
+ RET(FALSE)
+ if (!(*pfi_uar)((**ppr_tree).data))
+ RET(FALSE)
+ if (!tree_trav(&(**ppr_tree).right, pfi_uar))
+ RET(FALSE)
+ RET(TRUE)
+}
+
+
+void
+tree_mung(ppr_tree, pfv_uar)
+ tree **ppr_tree;
+ void (*pfv_uar)();
+{
+ ENTER("tree_mung")
+ if (*ppr_tree) {
+ tree_mung(&(**ppr_tree).left, pfv_uar);
+ tree_mung(&(**ppr_tree).right, pfv_uar);
+ if (pfv_uar)
+ (*pfv_uar)((**ppr_tree).data);
+ free(*ppr_tree);
+ *ppr_tree = NULL;
+ }
+ RETV
+}
+
+
+static tree *
+sprout(ppr, p_data, pi_balance, pfi_compare, pfv_delete)
+ tree **ppr;
+ tree_t p_data;
+ int *pi_balance;
+ int (*pfi_compare)();
+ void (*pfv_delete)();
+{
+ tree *p1, *p2, *sub;
+ int cmp;
+
+ ENTER("sprout")
+
+ /* are we grounded? if so, add the node "here" and set the rebalance
+ * flag, then exit.
+ */
+ if (!*ppr) {
+ MSG("grounded. adding new node, setting h=true")
+ *ppr = (tree *) malloc(sizeof(tree));
+ if (*ppr) {
+ (*ppr)->left = NULL;
+ (*ppr)->right = NULL;
+ (*ppr)->bal = 0;
+ (*ppr)->data = p_data;
+ *pi_balance = TRUE;
+ }
+ RET(*ppr);
+ }
+
+ /* compare the data using routine passed by caller.
+ */
+ cmp = (*pfi_compare)(p_data, (*ppr)->data);
+
+ /* if LESS, prepare to move to the left.
+ */
+ if (cmp < 0) {
+ MSG("LESS. sprouting left.")
+ sub = sprout(&(*ppr)->left, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) { /* left branch has grown */
+ MSG("LESS: left branch has grown")
+ switch ((*ppr)->bal) {
+ case 1: /* right branch WAS longer; bal is ok now */
+ MSG("LESS: case 1.. bal restored implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0: /* balance WAS okay; now left branch longer */
+ MSG("LESS: case 0.. balnce bad but still ok")
+ (*ppr)->bal = -1;
+ break;
+ case -1: /* left branch was already too long. rebal */
+ MSG("LESS: case -1: rebalancing")
+ p1 = (*ppr)->left;
+ if (p1->bal == -1) { /* LL */
+ MSG("LESS: single LL")
+ (*ppr)->left = p1->right;
+ p1->right = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double LR */
+ MSG("LESS: double LR")
+
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+
+ (*ppr)->left = p2->right;
+ p2->right = *ppr;
+
+ if (p2->bal == -1)
+ (*ppr)->bal = 1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* if MORE, prepare to move to the right.
+ */
+ if (cmp > 0) {
+ MSG("MORE: sprouting to the right")
+ sub = sprout(&(*ppr)->right, p_data, pi_balance,
+ pfi_compare, pfv_delete);
+ if (sub && *pi_balance) {
+ MSG("MORE: right branch has grown")
+
+ switch ((*ppr)->bal) {
+ case -1:
+ MSG("MORE: balance was off, fixed implicitly")
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ break;
+ case 0:
+ MSG("MORE: balance was okay, now off but ok")
+ (*ppr)->bal = 1;
+ break;
+ case 1:
+ MSG("MORE: balance was off, need to rebalance")
+ p1 = (*ppr)->right;
+ if (p1->bal == 1) { /* RR */
+ MSG("MORE: single RR")
+ (*ppr)->right = p1->left;
+ p1->left = *ppr;
+ (*ppr)->bal = 0;
+ *ppr = p1;
+ } else { /* double RL */
+ MSG("MORE: double RL")
+
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+
+ (*ppr)->right = p2->left;
+ p2->left = *ppr;
+
+ if (p2->bal == 1)
+ (*ppr)->bal = -1;
+ else
+ (*ppr)->bal = 0;
+
+ if (p2->bal == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+
+ *ppr = p2;
+ } /*else*/
+ (*ppr)->bal = 0;
+ *pi_balance = FALSE;
+ } /*switch*/
+ } /*if*/
+ RET(sub)
+ } /*if*/
+
+ /* not less, not more: this is the same key! replace...
+ */
+ MSG("FOUND: Replacing data value")
+ *pi_balance = FALSE;
+ if (pfv_delete)
+ (*pfv_delete)((*ppr)->data);
+ (*ppr)->data = p_data;
+ RET(*ppr)
+}
+
+
+static int
+delete(ppr_p, pfi_compare, p_user, pfv_uar, pi_balance, pi_uar_called)
+ tree **ppr_p;
+ int (*pfi_compare)();
+ tree_t p_user;
+ void (*pfv_uar)();
+ int *pi_balance;
+ int *pi_uar_called;
+{
+ tree *pr_q;
+ int i_comp, i_ret;
+
+ ENTER("delete")
+
+ if (*ppr_p == NULL) {
+ MSG("key not in tree")
+ RET(FALSE)
+ }
+
+ i_comp = (*pfi_compare)((*ppr_p)->data, p_user);
+ if (i_comp > 0) {
+ MSG("too high - scan left")
+ i_ret = delete(&(*ppr_p)->left, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ } else if (i_comp < 0) {
+ MSG("too low - scan right")
+ i_ret = delete(&(*ppr_p)->right, pfi_compare, p_user, pfv_uar,
+ pi_balance, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_p, pi_balance);
+ } else {
+ MSG("equal")
+ pr_q = *ppr_p;
+ if (pr_q->right == NULL) {
+ MSG("right subtree null")
+ *ppr_p = pr_q->left;
+ *pi_balance = TRUE;
+ } else if (pr_q->left == NULL) {
+ MSG("right subtree non-null, left subtree null")
+ *ppr_p = pr_q->right;
+ *pi_balance = TRUE;
+ } else {
+ MSG("neither subtree null")
+ del(&pr_q->left, pi_balance, &pr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_L(ppr_p, pi_balance);
+ }
+ if (!*pi_uar_called && pfv_uar)
+ (*pfv_uar)(pr_q->data);
+ free(pr_q); /* thanks to wuth@castrov.cuc.ab.ca */
+ i_ret = TRUE;
+ }
+ RET(i_ret)
+}
+
+
+static void
+del(ppr_r, pi_balance, ppr_q, pfv_uar, pi_uar_called)
+ tree **ppr_r;
+ int *pi_balance;
+ tree **ppr_q;
+ void (*pfv_uar)();
+ int *pi_uar_called;
+{
+ ENTER("del")
+
+ if ((*ppr_r)->right != NULL) {
+ del(&(*ppr_r)->right, pi_balance, ppr_q,
+ pfv_uar, pi_uar_called);
+ if (*pi_balance)
+ bal_R(ppr_r, pi_balance);
+ } else {
+ if (pfv_uar)
+ (*pfv_uar)((*ppr_q)->data);
+ *pi_uar_called = TRUE;
+ (*ppr_q)->data = (*ppr_r)->data;
+ *ppr_q = *ppr_r;
+ *ppr_r = (*ppr_r)->left;
+ *pi_balance = TRUE;
+ }
+
+ RETV
+}
+
+
+static void
+bal_L(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_L")
+ MSG("left branch has shrunk")
+
+ switch ((*ppr_p)->bal) {
+ case -1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = 1;
+ *pi_balance = FALSE;
+ break;
+ case 1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->right;
+ b1 = p1->bal;
+ if (b1 >= 0) {
+ MSG("single RR")
+ (*ppr_p)->right = p1->left;
+ p1->left = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = 1;
+ p1->bal = -1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double RL")
+ p2 = p1->left;
+ b2 = p2->bal;
+ p1->left = p2->right;
+ p2->right = p1;
+ (*ppr_p)->right = p2->left;
+ p2->left = *ppr_p;
+ if (b2 == 1)
+ (*ppr_p)->bal = -1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == -1)
+ p1->bal = 1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
+
+
+static void
+bal_R(ppr_p, pi_balance)
+ tree **ppr_p;
+ int *pi_balance;
+{
+ tree *p1, *p2;
+ int b1, b2;
+
+ ENTER("bal_R")
+ MSG("right branch has shrunk")
+ switch ((*ppr_p)->bal) {
+ case 1:
+ MSG("was imbalanced, fixed implicitly")
+ (*ppr_p)->bal = 0;
+ break;
+ case 0:
+ MSG("was okay, is now one off")
+ (*ppr_p)->bal = -1;
+ *pi_balance = FALSE;
+ break;
+ case -1:
+ MSG("was already off, this is too much")
+ p1 = (*ppr_p)->left;
+ b1 = p1->bal;
+ if (b1 <= 0) {
+ MSG("single LL")
+ (*ppr_p)->left = p1->right;
+ p1->right = *ppr_p;
+ if (b1 == 0) {
+ MSG("b1 == 0")
+ (*ppr_p)->bal = -1;
+ p1->bal = 1;
+ *pi_balance = FALSE;
+ } else {
+ MSG("b1 != 0")
+ (*ppr_p)->bal = 0;
+ p1->bal = 0;
+ }
+ *ppr_p = p1;
+ } else {
+ MSG("double LR")
+ p2 = p1->right;
+ b2 = p2->bal;
+ p1->right = p2->left;
+ p2->left = p1;
+ (*ppr_p)->left = p2->right;
+ p2->right = *ppr_p;
+ if (b2 == -1)
+ (*ppr_p)->bal = 1;
+ else
+ (*ppr_p)->bal = 0;
+ if (b2 == 1)
+ p1->bal = -1;
+ else
+ p1->bal = 0;
+ *ppr_p = p2;
+ p2->bal = 0;
+ }
+ }
+ RETV
+}
diff --git a/usr.sbin/named/tree.h b/usr.sbin/named/tree.h
new file mode 100644
index 0000000..2cad7c1
--- /dev/null
+++ b/usr.sbin/named/tree.h
@@ -0,0 +1,48 @@
+/* tree.h - declare structures used by tree library
+ *
+ * vix 22jan93 [revisited; uses RCS, ANSI, POSIX; has bug fixes]
+ * vix 27jun86 [broken out of tree.c]
+ *
+ * $Id: tree.h,v 1.1 1994/04/09 04:05:46 vixie Exp $
+ */
+
+
+#ifndef _TREE_H_INCLUDED
+#define _TREE_H_INCLUDED
+
+
+#ifndef __P
+# if defined(__STDC__) || defined(__GNUC__)
+# define __P(x) x
+# else
+# define __P(x) ()
+# endif
+#endif
+
+/*
+ * tree_t is our package-specific anonymous pointer.
+ */
+#if defined(__STDC__) || defined(__GNUC__)
+typedef void *tree_t;
+#else
+typedef char *tree_t;
+#endif
+
+
+typedef struct tree_s {
+ tree_t data;
+ struct tree_s *left, *right;
+ short bal;
+ }
+ tree;
+
+
+void tree_init __P((tree **));
+tree_t tree_srch __P((tree **, int (*)(), tree_t));
+tree_t tree_add __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_delete __P((tree **, int (*)(), tree_t, void (*)()));
+int tree_trav __P((tree **, int (*)()));
+void tree_mung __P((tree **, void (*)()));
+
+
+#endif /* _TREE_H_INCLUDED */
diff --git a/usr.sbin/named/tree.man3 b/usr.sbin/named/tree.man3
new file mode 100644
index 0000000..5be48783
--- /dev/null
+++ b/usr.sbin/named/tree.man3
@@ -0,0 +1,154 @@
+.TH TREE 3 "5 April 1994"
+.\" from .TH TREE 3 "22 Jan 1993"
+.\" from .TH TREE 2 "23 June 1986"
+.UC 4
+.SH NAME
+tree_init, tree_mung, tree_srch, tree_add, tree_delete, tree_trav
+\- balanced binary tree routines
+.SH SYNOPSIS
+.nf
+.B void
+.B tree_init(tree)
+.B void **tree;
+.PP
+.B void *
+.B tree_srch(tree, compare, data)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.PP
+.B void
+.B tree_add(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_delete(tree, compare, data, del_uar)
+.B void **tree;
+.B int (*compare)();
+.B void *data;
+.B void (*del_uar)();
+.PP
+.B int
+.B tree_trav(tree, trav_uar)
+.B void **tree;
+.B int (*trav_uar)();
+.PP
+.B void
+.B tree_mung(tree, del_uar)
+.B void **tree;
+.B void (*del_uar)();
+.fi
+.SH DESCRIPTION
+These functions create and manipulate a balanced binary (AVL) tree. Each node
+of the tree contains the expected left & right subtree pointers, a short int
+balance indicator, and a pointer to the user data. On a 32 bit system, this
+means an overhead of 4+4+2+4 bytes per node (or, on a RISC or otherwise
+alignment constrained system with implied padding, 4+4+4+4 bytes per node).
+There is no key data type enforced by this package; a caller supplied
+compare routine is used to compare user data blocks.
+.PP
+Balanced binary trees are very fast on searches and replacements, but have a
+moderately high cost for additions and deletions. If your application does a
+lot more searches and replacements than it does additions and deletions, the
+balanced (AVL) binary tree is a good choice for a data structure.
+.PP
+.I Tree_init
+creates an empty tree and binds it to
+.I tree
+(which for this and all other routines in this package should be declared as
+a pointer to void or int, and passed by reference), which can then be used by
+other routines in this package. Note that more than one
+.I tree
+variable can exist at once; thus multiple trees can be manipulated
+simultaneously.
+.PP
+.I Tree_srch
+searches a tree for a specific node and returns either
+.I NULL
+if no node was found, or the value of the user data pointer if the node
+was found.
+.I compare
+is the address of a function to compare two user data blocks. This routine
+should work much the way
+.IR strcmp (3)
+does; in fact,
+.I strcmp
+could be used if the user data was a \s-2NUL\s+2 terminated string.
+.I data
+is the address of a user data block to be used by
+.I compare
+as the search criteria. The tree is searched for a node where
+.I compare
+returns 0.
+.PP
+.I Tree_add
+inserts or replaces a node in the specified tree. The tree specified by
+.I tree
+is searched as in
+.I tree_srch,
+and if a node is found to match
+.I data,
+then the
+.I del_uar
+function, if non\-\s-2NULL\s+2, is called with the address of the user data
+block for the node (this routine should deallocate any dynamic memory which
+is referenced exclusively by the node); the user data pointer for the node
+is then replaced by the value of
+.I data.
+If no node is found to match, a new node is added (which may or may not
+cause a transparent rebalance operation), with a user data pointer equal to
+.I data.
+A rebalance may or may not occur, depending on where the node is added
+and what the rest of the tree looks like.
+.I Tree_add
+will return the
+.I data
+pointer unless catastrophe occurs in which case it will return \s-2NULL\s+2.
+.PP
+.I Tree_delete
+deletes a node from
+.I tree.
+A rebalance may or may not occur, depending on where the node is removed from
+and what the rest of the tree looks like.
+.I Tree_delete
+returns TRUE if a node was deleted, FALSE otherwise.
+.PP
+.I Tree_trav
+traverses all of
+.I tree,
+calling
+.I trav_uar
+with the address of each user data block. If
+.I trav_uar
+returns FALSE at any time,
+.I tree_trav
+will immediately return FALSE to its caller. Otherwise all nodes will be
+reached and
+.I tree_trav
+will return TRUE.
+.PP
+.I Tree_mung
+deletes every node in
+.I tree,
+calling
+.I del_uar
+(if it is not \s-2NULL\s+2) with the user data address from each node (see
+.I tree_add
+and
+.I tree_delete
+above). The tree is left in the same state that
+.I tree_init
+leaves it in \- i.e., empty.
+.SH BUGS
+Should have a way for the caller to specify application specific
+.I malloc
+and
+.I free
+functions to be used internally when allocating meta data.
+.SH AUTHOR
+Paul Vixie, converted and augumented from Modula\-2 examples in
+.I Algorithms & Data Structures,
+Niklaus Wirth, Prentice\-Hall, ISBN 0\-13\-022005\-1.
diff --git a/usr.sbin/named/xfer/Makefile b/usr.sbin/named/xfer/Makefile
new file mode 100644
index 0000000..16a93c8
--- /dev/null
+++ b/usr.sbin/named/xfer/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 5.1 (Berkeley) 5/28/90
+
+PROG= named-xfer
+SRCS= named-xfer.c db_glue.c
+CFLAGS+=-I${.CURDIR}/..
+.PATH: ${.CURDIR}/..
+BINDIR= /usr/libexec
+NOMAN= noman
+
+.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 0000000..54ae2be
--- /dev/null
+++ b/usr.sbin/named/xfer/named-xfer.8
@@ -0,0 +1,146 @@
+.\" ++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
+.\"
+.TH @XFER_INDOT_U@NAMED-XFER @SYS_OPS_EXT_U@ "June 26, 1993"
+.UC 4
+.SH NAME
+@XFER_INDOT@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 @INDOT@named (@SYS_OPS_EXT@)
+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(@LIB_NETWORK_EXT@) 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. See the ``stubs'' directive in
+.IR @INDOT@named (@SYS_OPS_EXT@)
+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"
+@INDOT@named(@SYS_OPS_EXT@), resolver(@LIB_NETWORK_EXT@), resolver(@FORMAT_EXT@), hostname(@DESC_EXT@),
+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 0000000..b2546d0
--- /dev/null
+++ b/usr.sbin/named/xfer/named-xfer.c
@@ -0,0 +1,1487 @@
+/*
+ * 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.
+ * Modified extensively since then by just about everybody.
+ */
+
+/*
+ * ++Copyright++ 1988, 1990
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+#if !defined(lint) && !defined(SABER)
+char copyright[] =
+"@(#) Copyright (c) 1988, 1990 The Regents of the University of California.\n\
+ portions Copyright (c) 1993 Digital Equipment Corporation\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#if !defined(lint) && !defined(SABER)
+static char sccsid[] = "@(#)named-xfer.c 4.18 (Berkeley) 3/7/91";
+static char rcsid[] = "$Id: named-xfer.c,v 4.9.1.23 1994/07/22 08:42:39 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <netinet/in.h>
+#include <netiso/iso.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+
+#include <errno.h>
+#include <resolv.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <math.h>
+#include <signal.h>
+
+#define MAIN_PROGRAM
+#include "named.h"
+#undef MAIN_PROGRAM
+
+#ifndef LOG_PERROR
+# define LOG_PERROR 0
+#endif
+
+static struct zoneinfo zone; /* zone information */
+
+static char ddtfilename[] = _PATH_TMPXFER,
+ *ddtfile = ddtfilename,
+ *tmpname,
+ *domain; /* domain being xfered */
+
+static int quiet = 0,
+ read_interrupted = 0,
+ domain_len; /* strlen(domain) */
+
+static FILE *fp = NULL,
+ *dbfp = NULL;
+
+static void usage __P((const char *));
+static int getzone __P((struct zoneinfo *, u_int32_t, int)),
+ soa_zinfo __P((struct zoneinfo *, u_char *, u_char *)),
+ print_output __P((u_char *, int, u_char *)),
+ netread __P((int, char *, int, int));
+static SIG_FN read_alarm __P((void));
+static char *ProgName;
+
+extern char *optarg;
+extern int optind, getopt();
+
+void
+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, fd, closed = 0;
+ u_int32_t serial_no = 0;
+ u_int16_t port = htons(NAMESERVER_PORT);
+ struct stat statbuf;
+#ifdef STUBS
+ int stub_only = 0;
+#endif
+#ifdef GEN_AXFR
+ int class = C_IN;
+#endif
+
+ if (ProgName = strrchr(argv[0], '/'))
+ ProgName++;
+ else
+ ProgName = argv[0];
+
+ (void) umask(022);
+
+ /* this is a hack; closing everything in the parent is hard. */
+ for (fd = getdtablesize()-1; fd > STDERR_FILENO; fd--)
+ closed += (close(fd) == 0);
+
+#ifdef RENICE
+ nice (-40); /* this is the recommended procedure to */
+ nice (20); /* reset the priority of the current process */
+ nice (0); /* to "normal" (== 0) - see nice(3) */
+#endif
+
+#ifdef LOG_DAEMON
+ openlog(ProgName, LOG_PID|LOG_CONS|LOG_PERROR, LOGFAC);
+#else
+ openlog(ProgName, LOG_PID);
+#endif
+#ifdef STUBS
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:qS")) != EOF)
+#else
+ while ((c = getopt(argc, argv, "C:d:l:s:t:z:f:p:P:q")) != EOF)
+#endif
+ switch (c) {
+#ifdef GEN_AXFR
+ case 'C':
+ class = get_class(optarg);
+ break;
+#endif
+ case 'd':
+#ifdef DEBUG
+ debug = atoi(optarg);
+#endif
+ break;
+ case 'l':
+ ddtfile = (char *)malloc(strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+#ifdef SHORT_FNAMES
+ filenamecpy(ddtfile, optarg);
+#else
+ (void) strcpy(ddtfile, optarg);
+#endif /* SHORT_FNAMES */
+ (void) strcat(ddtfile, ".XXXXXX");
+ break;
+ case 's':
+ serial_no = strtoul(optarg, (char **)NULL, 10);
+ break;
+ case 't':
+ tracefile = optarg;
+ break;
+ case 'z': /* zone == domain */
+ domain = optarg;
+ domain_len = strlen(domain);
+ while ((domain_len > 0) &&
+ (domain[domain_len-1] == '.'))
+ domain[--domain_len] = '\0';
+ break;
+ case 'f':
+ dbfile = optarg;
+ tmpname = (char *)malloc((unsigned)strlen(optarg) +
+ sizeof(".XXXXXX") + 1);
+#ifdef SHORT_FNAMES
+ filenamecpy(tmpname, optarg);
+#else
+ (void) strcpy(tmpname, optarg);
+#endif /* SHORT_FNAMES */
+ break;
+ case 'p':
+ port = htons((u_int16_t)atoi(optarg));
+ break;
+ case 'P':
+ port = (u_int16_t)atoi(optarg);
+ break;
+#ifdef STUBS
+ case 'S':
+ stub_only = 1;
+ break;
+#endif
+ case 'q':
+ quiet++;
+ break;
+ case '?':
+ default:
+ usage("unrecognized argument");
+ /* NOTREACHED */
+ }
+
+ if (!domain || !dbfile || optind >= argc) {
+ if (!domain)
+ usage("no domain");
+ if (!dbfile)
+ usage("no dbfile");
+ if (optind >= argc)
+ usage("not enough arguments");
+ /* NOTREACHED */
+ }
+ if (stat(dbfile, &statbuf) != -1 &&
+ !S_ISREG(statbuf.st_mode) &&
+ !S_ISFIFO(statbuf.st_mode))
+ usage("dbfile must be a regular file or FIFO");
+ 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 HAVE_FCHMOD
+ if (fchmod(dbfd, 0644) == -1)
+#else
+ if (chmod(tmpname, 0644) == -1)
+#endif
+ {
+ perror(tmpname);
+ if (!quiet)
+ syslog(LOG_ERR, "can't [f]chmod 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;
+ }
+#if HAVE_FCHMOD
+ else if (fchmod(ddtd, 0644) == -1)
+#else
+ else if (chmod(ddtfile, 0644) == -1)
+#endif
+ {
+ 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);
+#ifdef SIGSYS
+ (void) signal(SIGSYS, SIG_IGN);
+#endif
+#ifdef DEBUG
+ if (debug == 0)
+#endif
+ {
+ (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 */
+
+ dprintf(1, (ddt,
+ "domain `%s'; file `%s'; serial %lu; closed %d\n",
+ domain, dbfile, serial_no, closed));
+
+ buildservicelist();
+ buildprotolist();
+
+ /* init zone data */
+
+ zp = &zone;
+#ifdef STUBS
+ if (stub_only)
+ zp->z_type = Z_STUB;
+ else
+#endif
+ zp->z_type = Z_SECONDARY;
+#ifdef GEN_AXFR
+ zp->z_class = class;
+#endif
+ zp->z_origin = domain;
+ zp->z_source = dbfile;
+ zp->z_addrcnt = 0;
+ dprintf(1, (ddt, "zone found (%d): \"%s\", source = %s\n",
+ zp->z_type,
+ (zp->z_origin[0] == '\0')
+ ? "."
+ : zp->z_origin,
+ zp->z_source));
+
+ for (; optind != argc; optind++, zp->z_addrcnt++) {
+ tm = argv[optind];
+ if (!inet_aton(tm, &zp->z_addr[zp->z_addrcnt])) {
+ hp = gethostbyname(tm);
+ if (hp == NULL) {
+ syslog(LOG_NOTICE,
+ "uninterpretable server (%s) for %s\n",
+ tm, zp->z_origin);
+ zp->z_addrcnt--; /* hack */
+ continue;
+ }
+ bcopy(hp->h_addr,
+ (char *)&zp->z_addr[zp->z_addrcnt],
+ INADDRSZ);
+ dprintf(1, (ddt, "Arg: \"%s\"\n", tm));
+ }
+ if (zp->z_addr[zp->z_addrcnt].s_addr == 0) {
+ syslog(LOG_NOTICE,
+ "SOA query to localhost (%s) for %s",
+ tm, zp->z_origin);
+ zp->z_addrcnt--; /* hack */
+ continue;
+ }
+ if (zp->z_addrcnt >= NSMAX) {
+ zp->z_addrcnt = NSMAX;
+ dprintf(1, (ddt, "NSMAX reached\n"));
+ break;
+ }
+ }
+ dprintf(1, (ddt, "addrcnt = %d\n", zp->z_addrcnt));
+
+ _res.options &= ~(RES_DEFNAMES | RES_DNSRCH | RES_RECURSE);
+ result = getzone(zp, serial_no, port);
+ (void) my_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 */
+ }
+ /*NOTREACHED*/
+}
+
+static char *UsageText[] = {
+ "\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]\n",
+ "\t[-t trace_file]\n",
+ "\t[-p port]\n",
+#ifdef STUBS
+ "\t[-S]\n",
+#endif
+#ifdef GEN_AXFR
+ "\t[-C class]\n",
+#endif
+ "\tservers...\n",
+ NULL
+};
+
+static void
+usage(msg)
+ const char *msg;
+{
+ char * const *line;
+
+ fprintf(stderr, "Usage error: %s\n", msg);
+ fprintf(stderr, "Usage: %s\n", ProgName);
+ for (line = UsageText; *line; line++)
+ fputs(*line, stderr);
+ exit(XFER_FAIL);
+}
+
+#define DEF_DNAME '\001' /* '\0' means the root domain */
+/* XXX: The following variables should probably all be "static" */
+int minimum_ttl = 0, got_soa = 0;
+int prev_comment = 0; /* was previous record a comment? */
+char zone_top[MAXDNAME]; /* the top of the zone */
+char prev_origin[MAXDNAME]; /* from most recent $ORIGIN line */
+char prev_dname[MAXDNAME] = { DEF_DNAME }; /* from previous record */
+char prev_ns_dname[MAXDNAME] = { DEF_DNAME }; /* from most recent NS record */
+
+static int
+getzone(zp, serial_no, port)
+ struct zoneinfo *zp;
+ u_int32_t serial_no;
+ int port;
+{
+ HEADER *hp;
+ u_int16_t len;
+ u_int32_t serial;
+ int s, n, l, cnt, nscnt, soacnt, error = 0;
+ u_char *cp, *nmp, *eom, *tmp ;
+ u_char *buf = NULL;
+ int bufsize;
+ char name[MAXDNAME], name2[MAXDNAME];
+ struct sockaddr_in sin;
+ struct zoneinfo zp_start, zp_finish;
+#ifdef POSIX_SIGNALS
+ struct sigaction sv, osv;
+#else
+ struct sigvec sv, osv;
+#endif
+ int ancount, aucount;
+ int Class;
+#ifdef DEBUG
+ if (debug) {
+ (void)fprintf(ddt,"getzone() %s ", zp->z_origin);
+ switch (zp->z_type) {
+ case Z_STUB:
+ fprintf(ddt,"stub\n");
+ break;
+ case Z_SECONDARY:
+ fprintf(ddt,"secondary\n");
+ break;
+ default:
+ fprintf(ddt,"unknown type\n");
+ }
+ }
+#endif
+#ifdef POSIX_SIGNALS
+ sv.sa_handler = read_alarm;
+ /* SA_ONSTACK isn't recommended for strict POSIX code */
+ /* is it absolutely necessary? */
+ /* sv.sa_flags = SA_ONSTACK; */
+ sigfillset(&sv.sa_mask);
+ (void) sigaction(SIGALRM, &sv, &osv);
+#else
+ sv.sv_handler = read_alarm;
+ sv.sv_onstack = 0;
+ sv.sv_mask = ~0;
+ (void) sigvec(SIGALRM, &sv, &osv);
+#endif
+
+ strcpy(zone_top, zp->z_origin);
+ if ((l = strlen(zone_top)) != 0 && zone_top[l - 1] == '.')
+ zone_top[l - 1] = '\0';
+ strcpy(prev_origin, zone_top);
+
+ for (cnt = 0; cnt < zp->z_addrcnt; cnt++) {
+#ifdef GEN_AXFR
+ Class = zp->z_class;
+#else
+ Class = C_IN;
+#endif
+ 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 = (u_int16_t)port;
+ sin.sin_addr = zp->z_addr[cnt];
+ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket: %m");
+ error++;
+ break;
+ }
+ dprintf(2, (ddt, "connecting to server #%d [%s].%d\n",
+ cnt+1, inet_ntoa(sin.sin_addr),
+ ntohs(sin.sin_port)));
+ if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
+ syslog(LOG_ERR, "connect(%s) failed: %m",
+ inet_ntoa(sin.sin_addr));
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+tryagain:
+ n = res_mkquery(QUERY, zp->z_origin, Class,
+ T_SOA, NULL, 0, NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet)
+ syslog(LOG_NOTICE,
+ "zone %s: res_mkquery T_SOA failed",
+ zp->z_origin);
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & message for SOA query
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_ERR, "writemsg: %m");
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ /*
+ * Get out your butterfly net and catch the SOA
+ */
+ if (netread(s, (char *)buf, INT16SZ, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ if ((len = _getshort(buf)) == 0) {
+ (void) my_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) my_close(s);
+ continue;
+ }
+ bufsize = len;
+ }
+ if (netread(s, (char *)buf, len, XFER_TIMER) < 0) {
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+#ifdef DEBUG
+ if (debug >= 3) {
+ (void)fprintf(ddt,"len = %d\n", len);
+ fp_query(buf, ddt);
+ }
+#endif
+ 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)) {
+#ifndef GEN_AXFR
+ if (Class == C_IN) {
+ dprintf(1, (ddt, "SOA failed, trying C_HS\n"));
+ Class = C_HS;
+ goto tryagain;
+ }
+#endif
+ syslog(LOG_NOTICE,
+ "%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);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ zp_start = *zp;
+ if (len < HFIXEDSZ + QFIXEDSZ) {
+ badsoa:
+ syslog(LOG_NOTICE,
+ "malformed SOA from [%s], zone %s: too short\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin);
+ error++;
+ (void) my_close(s);
+ continue;
+ }
+ tmp = buf + HFIXEDSZ;
+ 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 (SEQ_GT(zp_start.z_serial, serial_no) || !serial_no) {
+ dprintf(1, (ddt, "need update, serial %d\n",
+ zp_start.z_serial));
+ hp = (HEADER *) buf;
+ soacnt = 0;
+ nscnt = 0;
+ gettime (&tt);
+ (void) fprintf (dbfp, "; zone '%s' last serial %lu\n",
+ domain, serial_no);
+ (void) fprintf (dbfp, "; from %s at %s",
+ inet_ntoa (sin.sin_addr),
+ ctime (&tt.tv_sec));
+ for (;;) {
+ if ((soacnt == 0) || (zp->z_type == Z_STUB)) {
+ int type;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ if (!soacnt)
+ type = T_SOA;
+ else if (!nscnt)
+ type = T_NS;
+ else
+ type = T_SOA;
+ } else
+#endif
+ type = T_AXFR;
+ n = res_mkquery(QUERY, zp->z_origin,
+ Class, type, NULL, 0,
+ NULL, buf, bufsize);
+ if (n < 0) {
+ if (!quiet) {
+#ifdef STUBS
+ if (zp->z_type == Z_STUB)
+ syslog(LOG_NOTICE,
+ (type == T_SOA)
+ ? "zone %s: res_mkquery T_SOA failed"
+ : "zone %s: res_mkquery T_NS failed",
+ zp->z_origin);
+ else
+#endif
+ syslog(LOG_NOTICE,
+ "zone %s: res_mkquery T_AXFR failed",
+ zp->z_origin);
+ }
+ (void) my_close(s);
+#ifdef POSIX_SIGNALS
+ sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ sigvec(SIGALRM, &osv,
+ (struct sigvec *)0);
+#endif
+ return (XFER_FAIL);
+ }
+ /*
+ * Send length & msg for zone transfer
+ */
+ if (writemsg(s, buf, n) < 0) {
+ syslog(LOG_ERR,"writemsg: %m");
+ error++;
+ (void) my_close(s);
+ break;
+ }
+ }
+ /*
+ * Receive length & response
+ */
+ if (netread(s, (char *)buf, INT16SZ,
+ (soacnt == 0) ?300 :XFER_TIMER)
+ < 0) {
+ error++;
+ break;
+ }
+ if ((len = _getshort(buf)) == 0)
+ break;
+ eom = buf + len;
+ if (netread(s, (char *)buf, len, XFER_TIMER)
+ < 0) {
+ 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 < HFIXEDSZ) {
+ badrec:
+ error++;
+ syslog(LOG_NOTICE,
+ "record too short from [%s], zone %s\n",
+ inet_ntoa(sin.sin_addr),
+ zp->z_origin);
+ break;
+ }
+ cp = buf + HFIXEDSZ;
+ 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;
+#ifdef STUBS
+ if (zp->z_type == Z_STUB) {
+ ancount = ntohs(hp->ancount);
+ for (cnt = 0 ; cnt < ancount ; cnt++) {
+
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ if (hp->nscount) {
+ /* we should not get here */
+ ancount = ntohs(hp->nscount);
+ for (cnt = 0 ; cnt < ancount ; cnt++) {
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ }
+ ancount = ntohs(hp->arcount);
+ for (cnt = 0 ; cnt < ancount ; cnt ++) {
+ n = print_output(buf, bufsize, cp);
+ cp += n;
+ }
+ if (cp != eom) {
+ syslog(LOG_ERR,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, n, zp->z_origin);
+ error++;
+ break;
+ }
+
+ } else {
+#endif /*STUBS*/
+ n = print_output(buf, bufsize, cp);
+ if (cp + n != eom) {
+ syslog(LOG_ERR,
+ "print_output: short answer (%d, %d), zone %s",
+ cp - buf, n, zp->z_origin);
+ error++;
+ break;
+ }
+#ifdef STUBS
+ }
+#endif
+ 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 * INT16SZ
+ + INT32SZ) {
+ goto badsoa;
+ }
+ tmp += 2 * INT16SZ
+ + INT32SZ;
+ 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 <= INT32SZ)
+ goto badsoa;
+ GETLONG(serial, tmp);
+ dprintf(3, (ddt,
+ "first SOA for %s, serial %d\n",
+ name, serial));
+ continue;
+ }
+ if (dn_expand(buf, buf + 512, nmp,
+ name2, sizeof name2) == -1)
+ goto badsoa;
+ if (strcasecmp((char *)name,
+ (char *)name2) != 0) {
+ dprintf(2, (ddt,
+ "extraneous SOA for %s\n",
+ name2));
+ continue;
+ }
+ tmp -= INT16SZ;
+ if (soa_zinfo(&zp_finish, tmp, eom) == -1)
+ goto badsoa;
+ dprintf(2, (ddt,
+ "SOA, serial %d\n",
+ zp_finish.z_serial));
+ if (serial != zp_finish.z_serial) {
+ soacnt = 0;
+ got_soa = 0;
+ minimum_ttl = 0;
+ strcpy(prev_origin, zp->z_origin);
+ prev_dname[0] = DEF_DNAME;
+ dprintf(1, (ddt,
+ "serial changed, restart\n"
+ ));
+ /*
+ * 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;
+#ifdef STUBS
+ } else if (zp->z_type == Z_STUB && n == T_NS) {
+ nscnt++;
+ } else if (zp->z_type == Z_STUB) {
+ break;
+#endif
+ }
+ }
+ (void) my_close(s);
+ if (error == 0) {
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv,
+ (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ return (XFER_SUCCESS);
+ }
+ dprintf(2, (ddt, "error receiving zone transfer\n"));
+ } else if (zp_start.z_serial == serial_no) {
+ (void) my_close(s);
+ dprintf(1, (ddt,
+ "zone up-to-date, serial %u\n",
+ zp_start.z_serial));
+ return (XFER_UPTODATE);
+ } else {
+ (void) my_close(s);
+ if (!quiet)
+ syslog(LOG_NOTICE,
+ "serial from [%s], zone %s: %u lower than current: %u\n",
+ inet_ntoa(sin.sin_addr), zp->z_origin,
+ zp_start.z_serial, serial_no);
+ return (XFER_FAIL);
+ }
+ }
+#ifdef POSIX_SIGNALS
+ (void) sigaction(SIGALRM, &osv, (struct sigaction *)0);
+#else
+ (void) sigvec(SIGALRM, &osv, (struct sigvec *)0);
+#endif
+ if (error)
+ return (XFER_TIMEOUT);
+ return (XFER_FAIL);
+}
+
+/*
+ * Set flag saying to read was interrupted
+ * used for a read timer
+ */
+static SIG_FN
+read_alarm()
+{
+ read_interrupted = 1;
+}
+
+static int
+netread(fd, buf, len, timeout)
+ int fd;
+ register char *buf;
+ register int len;
+ int timeout;
+{
+ static const char setitimerStr[] = "setitimer: %m";
+ struct itimerval ival, zeroival;
+ register int n;
+#if defined(sun)
+ int retries = 0;
+#endif
+
+ memset(&zeroival, 0, sizeof zeroival);
+ ival = zeroival;
+ ival.it_value.tv_sec = timeout;
+ while (len > 0) {
+ if (setitimer(ITIMER_REAL, &ival, NULL) < 0) {
+ syslog(LOG_ERR, setitimerStr);
+ return (-1);
+ }
+ errno = 0;
+ n = recv(fd, buf, len, 0);
+ if (n <= 0) {
+ if (errno == 0) {
+#if defined(sun)
+ if (++retries < 42) /* doug adams */
+ continue;
+#endif
+ syslog(LOG_ERR,
+ "recv(len=%d): n=%d && !errno",
+ len, n);
+ return (-1);
+ }
+ if (errno == EINTR && !read_interrupted) {
+ /* Some other signal returned; ignore it. */
+ continue;
+ }
+ syslog(LOG_ERR, "recv(len=%d): %m", len);
+ return (-1);
+ }
+ buf += n;
+ len -= n;
+ }
+ if (setitimer(ITIMER_REAL, &zeroival, NULL) < 0) {
+ syslog(LOG_ERR, setitimerStr);
+ return (-1);
+ }
+ return (0);
+}
+
+static int
+soa_zinfo(zp, cp, eom)
+ register struct zoneinfo *zp;
+ register u_char *cp;
+ u_char *eom;
+{
+ register int n;
+
+ if (eom - cp < 3 * INT16SZ + INT32SZ)
+ return (-1);
+ cp += 3 * INT16SZ + INT32SZ;
+ 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 * INT32SZ)
+ return (-1);
+ GETLONG(zp->z_serial, cp);
+ GETLONG(zp->z_refresh, cp);
+ GETLONG(zp->z_retry, cp);
+ GETLONG(zp->z_expire, cp);
+ GETLONG(zp->z_minimum, cp);
+ return (0);
+}
+
+/*
+ * 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.
+ */
+static int
+print_output(msg, msglen, rrp)
+ u_char *msg;
+ int msglen;
+ u_char *rrp;
+{
+ register u_char *cp;
+ register HEADER *hp = (HEADER *) msg;
+ u_int32_t addr, ttl;
+ int i, j, tab, result, class, type, dlen, n1, n;
+ struct iso_addr isoa;
+ char data[BUFSIZ];
+ u_char *cp1, *cp2, *temp_ptr;
+ char *cdata, *origin, *proto, dname[MAXDNAME];
+ char *ignore = "";
+#ifdef NO_GLUE
+ int lend, lenn;
+#endif /*NO_GLUE*/
+
+ cp = rrp;
+ n = dn_expand(msg, msg + msglen, cp, dname, sizeof dname);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ GETSHORT(type, cp);
+ GETSHORT(class, cp);
+ GETLONG(ttl, cp);
+ GETSHORT(dlen, cp);
+
+ origin = strchr(dname, '.');
+ if (origin == NULL)
+ origin = "";
+ else
+ origin++; /* move past the '.' */
+ dprintf(3, (ddt,
+ "print_output: dname %s type %d class %d ttl %d\n",
+ dname, type, class, ttl));
+ /*
+ * 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_X25:
+ case T_ISDN:
+ 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:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 = (u_char *)data;
+ n = strlen(data) + 1;
+ break;
+
+ case T_MINFO:
+ case T_SOA:
+ case T_RP:
+ n = dn_expand(msg, msg + msglen, cp, data, sizeof data);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ n = strlen(data) + 1;
+ cp1 = (u_char *)data + n;
+ n1 = sizeof data - n;
+ if (type == T_SOA)
+ n1 -= 5 * INT32SZ;
+ n = dn_expand(msg, msg + msglen, cp, (char *)cp1, n1);
+ if (n < 0) {
+ hp->rcode = FORMERR;
+ return (-1);
+ }
+ cp += n;
+ cp1 += strlen((char *) cp1) + 1;
+ if (type == T_SOA) {
+ temp_ptr = cp + 4 * INT32SZ;
+ GETLONG(minimum_ttl, temp_ptr);
+ n = 5 * INT32SZ;
+ bcopy((char *) cp, (char *) cp1, n);
+ cp += n;
+ cp1 += n;
+ }
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ /* grab preference */
+ bcopy((char *)cp, data, INT16SZ);
+ cp1 = (u_char *)data + INT16SZ;
+ cp += INT16SZ;
+
+ /* get name */
+ n = dn_expand(msg, msg + msglen, cp,
+ (char *)cp1, sizeof data - INT16SZ);
+ if (n < 0)
+ return (-1);
+ cp += n;
+
+ /* compute end of data */
+ cp1 += strlen((char *) cp1) + 1;
+ /* compute size of data */
+ n = cp1 - (u_char *)data;
+ cp1 = (u_char *)data;
+ break;
+
+ default:
+ dprintf(3, (ddt, "unknown type %d\n", type));
+ return ((cp - rrp) + dlen);
+ }
+ if (n > MAXDATA) {
+ dprintf(1, (ddt,
+ "update type %d: %d bytes is too much data\n",
+ type, n));
+ 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++;
+ }
+
+#ifdef NO_GLUE
+ /*
+ * If they are trying to tell us info about something that is
+ * not in the zone that we are transfering, then ignore it!
+ * They don't have the authority to tell us this info.
+ *
+ * We have to do a bit of checking here - the name that we are
+ * checking vs is fully qualified & may be in a subdomain of the
+ * zone in question. We also need to ignore any final dots.
+ *
+ * If a domain has both NS records and non-NS records, (for
+ * example, NS and MX records), then we should ignore the non-NS
+ * records (except that we should not ignore glue A records).
+ * XXX: It is difficult to do this properly, so we just compare
+ * the current dname with that in the most recent NS record.
+ * This defends against the most common error case,
+ * where the remote server sends MX records soon after the
+ * NS records for a particular domain. If sent earlier, we lose. XXX
+ */
+ if (!samedomain(dname, domain)) {
+ (void) fprintf(dbfp, "; Ignoring info about %s, not in zone %s.\n",
+ dname, domain);
+ ignore = "; ";
+ } else if (type != T_NS && type != T_A &&
+ strcasecmp(zone_top, dname) != 0 &&
+ strcasecmp(prev_ns_dname, dname) == 0)
+ {
+ (void) fprintf(dbfp, "; Ignoring extra info about %s, invalid after NS delegation.\n",
+ dname);
+ ignore = "; ";
+ }
+#endif /*NO_GLUE*/
+
+ /*
+ * If the current record is not being ignored, but the
+ * previous record was ignored, then we invalidate information
+ * that might have been altered by ignored records.
+ * (This means that we sometimes output unnecessary $ORIGIN
+ * lines, but that is harmless.)
+ *
+ * Also update prev_comment now.
+ */
+ if (prev_comment && ignore[0] == '\0') {
+ prev_dname[0] = DEF_DNAME;
+ prev_origin[0] = DEF_DNAME;
+ }
+ prev_comment = (ignore[0] != '\0');
+
+ /*
+ * set prev_ns_dname if necessary
+ */
+ if (type == T_NS) {
+ (void) strcpy(prev_ns_dname, dname);
+ }
+
+ /*
+ * If the origin has changed, print the new origin
+ */
+ if (strcasecmp(prev_origin, origin)) {
+ (void) strcpy(prev_origin, origin);
+ (void) fprintf(dbfp, "%s$ORIGIN %s.\n", ignore, 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 = strchr(dname, '.');
+
+ (void) strcpy(prev_dname, dname);
+ if (cutp)
+ *cutp = '\0';
+
+ if (dname[0] == 0) {
+ if (origin[0] == 0)
+ (void) fprintf(dbfp, "%s.\t", ignore);
+ else
+ (void) fprintf(dbfp, "%s.%s.\t",
+ ignore, origin); /* ??? */
+ } else
+ (void) fprintf(dbfp, "%s%s\t", ignore, dname);
+ if (strlen(dname) < 8)
+ tab = 1;
+ } else {
+ (void) fprintf(dbfp, "%s\t", ignore);
+ 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:
+ case T_ISDN:
+ cp2 = cp + n;
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ (void) putc('"', dbfp);
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ (void) fputs("\" \"", dbfp);
+ n = *cp++;
+ cp1 = cp + n;
+ if (cp1 > cp2)
+ cp1 = cp2;
+ while (cp < cp1) {
+ if (*cp == '\0') {
+ cp = cp1;
+ break;
+ }
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ (void) fputs("\"\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, "%s\t\t%lu", ignore, 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:
+ case T_AFSDB:
+ case T_RT:
+ GETSHORT(n, cp);
+ (void) fprintf(dbfp, "%lu", n);
+ (void) fprintf(dbfp, " %s.\n", cp);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ cp1 = cp + n;
+ (void) putc('"', dbfp);
+ while (cp < cp1) {
+ if (i = *cp++) {
+ for (j = i ; j > 0 && cp < cp1 ; j--) {
+ if ((*cp == '\n') || (*cp == '"')) {
+ (void) putc('\\', dbfp);
+ }
+ (void) putc(*cp++, dbfp);
+ }
+ }
+ }
+ (void) fputs("\"\n", dbfp);
+ break;
+
+ case T_NSAP:
+ isoa.isoa_len = n;
+ if (isoa.isoa_len > sizeof(isoa.isoa_genaddr))
+ isoa.isoa_len = sizeof(isoa.isoa_genaddr);
+ bcopy(cp, isoa.isoa_genaddr, isoa.isoa_len);
+ fprintf(dbfp, "%s\n", iso_ntoa(&isoa));
+ break;
+
+ case T_UINFO:
+ (void) fprintf(dbfp, "\"%s\"\n", cp);
+ break;
+
+ case T_UID:
+ case T_GID:
+ if (n == INT32SZ) {
+ 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:
+ case T_RP:
+ (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);
+}
+
+#ifdef SHORT_FNAMES
+/*
+** This routine handles creating temporary files with mkstemp
+** in the presence of a 14 char filename system. Pathconf()
+** does not work over NFS.
+*/
+filenamecpy(ddtfile, optarg)
+char *ddtfile, *optarg;
+{
+ int namelen, extra, len;
+ char *dirname, *filename;
+
+ /* determine the length of filename allowed */
+ if((dirname = strrchr(optarg, '/')) == NULL){
+ filename = optarg;
+ } else {
+ *dirname++ = '\0';
+ filename = dirname;
+ }
+ namelen = pathconf(dirname == NULL? "." : optarg, _PC_NAME_MAX);
+ if(namelen <= 0)
+ namelen = 255; /* length could not be determined */
+ if(dirname != NULL)
+ *--dirname = '/';
+
+ /* copy a shorter name if it will be longer than allowed */
+ extra = (strlen(filename)+strlen(".XXXXXX")) - namelen;
+ if(extra > 0){
+ len = strlen(optarg) - extra;
+ (void) strncpy(ddtfile, optarg, len);
+ ddtfile[len] = '\0';
+ } else
+ (void) strcpy(ddtfile, optarg);
+}
+#endif /* SHORT_FNAMES */
diff --git a/usr.sbin/nfsd/Makefile b/usr.sbin/nfsd/Makefile
new file mode 100644
index 0000000..a881d5e
--- /dev/null
+++ b/usr.sbin/nfsd/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= nfsd
+CFLAGS+=-DNFS
+MAN8= nfsd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8
new file mode 100644
index 0000000..a54a564
--- /dev/null
+++ b/usr.sbin/nfsd/nfsd.8
@@ -0,0 +1,132 @@
+.\" 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.
+.\"
+.\" @(#)nfsd.8 8.3 (Berkeley) 2/22/94
+.\"
+.Dd February 22, 1994
+.Dt NFSD 8
+.Os
+.Sh NAME
+.Nm nfsd
+.Nd remote
+.Tn NFS
+server
+.Sh SYNOPSIS
+.Nm nfsd
+.Op Fl rut
+.Op Fl n Ar num_servers
+.Sh DESCRIPTION
+.Nm Nfsd
+runs on a server machine to service
+.Tn NFS
+requests from client machines.
+At least one
+.Nm nfsd
+must be running for a machine to operate as a server.
+.Pp
+Unless otherwise specified, four servers for
+.Tn UDP
+transport are started.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl r
+Register the
+.Tn NFS
+service with
+.Xr portmap 8
+without creating any servers.
+This option can be used along with the
+.Fl u
+or
+.Fl t
+options to re-register NFS if the portmap server is restarted.
+.It Fl n
+Specifies how many servers to create.
+.It Fl t
+Serve
+.Tn TCP NFS
+clients.
+.It Fl u
+Serve
+.Tn UDP NFS
+clients.
+.El
+.Pp
+For example,
+.Dq Li "nfsd -u -t 6"
+serves
+.Tn UDP
+and
+.Tn TCP
+transports using six daemons.
+.Pp
+A server should run enough daemons to handle
+the maximum level of concurrency from its clients,
+typically four to six.
+.Pp
+.Nm Nfsd
+listens for service requests at the port indicated in the
+.Tn NFS
+server specification; see
+.%T "Network File System Protocol Specification" ,
+RFC1094.
+.Pp
+If
+.Nm nfsd
+detects that
+.Tn NFS
+is not loaded in the running kernel, it will attempt
+to load a loadable kernel module containing
+.Tn NFS
+support using
+.Xr modload 8
+by way of
+.Xr vfsload 3 .
+If this fails, or no
+.Tn NFS
+LKM is available,
+.Nm nfsd
+will exit with an error.
+.Pp
+The
+.Nm nfsd
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr nfsstat 1 ,
+.Xr nfssvc 2 ,
+.Xr modload 8 ,
+.Xr mountd 8 ,
+.Xr portmap 8
+.Sh HISTORY
+The
+.Nm nfsd
+utility first appeared in 4.4BSD.
diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c
new file mode 100644
index 0000000..9d4d226
--- /dev/null
+++ b/usr.sbin/nfsd/nfsd.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 1989, 1993, 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)nfsd.c 8.7 (Berkeley) 2/22/94";
+#endif not lint
+
+#include <sys/param.h>
+#include <sys/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/uio.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+
+#ifdef ISO
+#include <netiso/iso.h>
+#endif
+#include <nfs/rpcv2.h>
+#include <nfs/nfsv2.h>
+#include <nfs/nfs.h>
+
+#ifdef KERBEROS
+#include <kerberosIV/des.h>
+#include <kerberosIV/krb.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+/* Global defs */
+#ifdef DEBUG
+#define syslog(e, s) fprintf(stderr,(s))
+int debug = 1;
+#else
+int debug = 0;
+#endif
+
+struct nfsd_srvargs nsd;
+char **Argv = NULL; /* pointer to argument vector */
+char *LastArg = NULL; /* end of argv */
+
+#ifdef KERBEROS
+char lnam[ANAME_SZ];
+KTEXT_ST kt;
+AUTH_DAT auth;
+char inst[INST_SZ];
+#endif
+
+void nonfs __P((int));
+void reapchild __P((int));
+void setproctitle __P((char *));
+void usage __P((void));
+
+/*
+ * Nfs server daemon mostly just a user context for nfssvc()
+ *
+ * 1 - do file descriptor and signal cleanup
+ * 2 - fork the nfsd(s)
+ * 3 - create server socket(s)
+ * 4 - register socket with portmap
+ *
+ * For connectionless protocols, just pass the socket into the kernel via.
+ * nfssvc().
+ * For connection based sockets, loop doing accepts. When you get a new
+ * socket from accept, pass the msgsock into the kernel via. nfssvc().
+ * The arguments are:
+ * -c - support iso cltp clients
+ * -r - reregister with portmapper
+ * -t - support tcp nfs clients
+ * -u - support udp nfs clients
+ * followed by "n" which is the number of nfsds' to fork off
+ */
+int
+main(argc, argv, envp)
+ int argc;
+ char *argv[], *envp[];
+{
+ extern int optind;
+ struct group *grp;
+ struct nfsd_args nfsdargs;
+ struct passwd *pwd;
+ struct ucred *cr;
+ struct sockaddr_in inetaddr, inetpeer;
+#ifdef ISO
+ struct sockaddr_iso isoaddr, isopeer;
+#endif
+ fd_set ready, sockbits;
+ int ch, cltpflag, connect_type_cnt, i, len, maxsock, msgsock;
+ int nfsdcnt, nfssvc_flag, on, reregister, sock, tcpflag, tcpsock;
+ int tp4cnt, tp4flag, tp4sock, tpipcnt, tpipflag, tpipsock, udpflag;
+ char *cp, **cpp;
+ struct vfsconf *vfc;
+
+ vfc = getvfsbyname("nfs");
+ if(!vfc && vfsisloadable("nfs")) {
+ if(vfsload("nfs"))
+ err(1, "vfsload(nfs)");
+ endvfsent(); /* flush cache */
+ vfc = getvfsbyname("nfs"); /* probably unnecessary */
+ }
+ if(!vfc) {
+ errx(1, "NFS is not available in the running kernel");
+ }
+
+ /* 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]);
+
+#define MAXNFSDCNT 20
+#define DEFNFSDCNT 4
+ nfsdcnt = DEFNFSDCNT;
+ cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
+ tpipflag = udpflag = 0;
+#ifdef ISO
+#define GETOPT "cn:rtu"
+#define USAGE "[-crtu] [-n num_servers]"
+#else
+#define GETOPT "n:rtu"
+#define USAGE "[-rtu] [-n num_servers]"
+#endif
+ while ((ch = getopt(argc, argv, GETOPT)) != EOF)
+ switch (ch) {
+ case 'n':
+ nfsdcnt = atoi(optarg);
+ if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
+ warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
+ nfsdcnt = DEFNFSDCNT;
+ }
+ break;
+ case 'r':
+ reregister = 1;
+ break;
+ case 't':
+ tcpflag = 1;
+ break;
+ case 'u':
+ udpflag = 1;
+ break;
+#ifdef ISO
+ case 'c':
+ cltpflag = 1;
+ break;
+#ifdef notyet
+ case 'i':
+ tp4cnt = 1;
+ break;
+ case 'p':
+ tpipcnt = 1;
+ break;
+#endif /* notyet */
+#endif /* ISO */
+ default:
+ case '?':
+ usage();
+ };
+ argv += optind;
+ argc -= optind;
+
+ /*
+ * XXX
+ * Backward compatibility, trailing number is the count of daemons.
+ */
+ if (argc > 1)
+ usage();
+ if (argc == 1) {
+ nfsdcnt = atoi(argv[0]);
+ if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
+ warnx("nfsd count %d; reset to %d", DEFNFSDCNT);
+ nfsdcnt = DEFNFSDCNT;
+ }
+ }
+
+ if (debug == 0) {
+ daemon(0, 0);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGSYS, nonfs);
+ (void)signal(SIGTERM, SIG_IGN);
+ }
+ (void)signal(SIGCHLD, reapchild);
+
+ if (reregister) {
+ if (udpflag &&
+ !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT))
+ err(1, "can't register with portmap for UDP.");
+ if (tcpflag &&
+ !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT))
+ err(1, "can't register with portmap for TCP.");
+ exit(0);
+ }
+ openlog("nfsd:", LOG_PID, LOG_DAEMON);
+
+ for (i = 0; i < nfsdcnt; i++) {
+ switch (fork()) {
+ case -1:
+ syslog(LOG_ERR, "fork: %m");
+ exit (1);
+ case 0:
+ break;
+ default:
+ continue;
+ }
+
+ setproctitle("nfsd-srv");
+ nfssvc_flag = NFSSVC_NFSD;
+ nsd.nsd_nfsd = NULL;
+#ifdef KERBEROS
+ nsd.nsd_authstr = (char *)kt.dat;
+#endif
+ while (nfssvc(nfssvc_flag, &nsd) < 0) {
+ if (errno != ENEEDAUTH) {
+ syslog(LOG_ERR, "nfssvc: %m");
+ exit(1);
+ }
+ nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
+#ifdef KERBEROS
+ kt.length = nsd.nsd_authlen;
+ kt.mbz = 0;
+ (void)strcpy(inst, "*");
+ if (krb_rd_req(&kt, "rcmd",
+ inst, nsd.nsd_haddr, &auth, "") == RD_AP_OK &&
+ krb_kntoln(&auth, lnam) == KSUCCESS &&
+ (pwd = getpwnam(lnam)) != NULL) {
+ cr = &nsd.nsd_cr;
+ cr->cr_uid = pwd->pw_uid;
+ cr->cr_groups[0] = pwd->pw_gid;
+ cr->cr_ngroups = 1;
+ setgrent();
+ while ((grp = getgrent()) != NULL) {
+ if (grp->gr_gid == cr->cr_groups[0])
+ continue;
+ for (cpp = grp->gr_mem;
+ *cpp != NULL; ++cpp)
+ if (!strcmp(*cpp, lnam))
+ break;
+ if (*cpp == NULL)
+ continue;
+ cr->cr_groups[cr->cr_ngroups++]
+ = grp->gr_gid;
+ if (cr->cr_ngroups == NGROUPS)
+ break;
+ }
+ endgrent();
+ nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHIN;
+ }
+#endif /* KERBEROS */
+ }
+ exit(0);
+ }
+
+ /* If we are serving udp, set up the socket. */
+ if (udpflag) {
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create udp socket");
+ exit(1);
+ }
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(sock,
+ (struct sockaddr *)&inetaddr, sizeof(inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind udp addr");
+ exit(1);
+ }
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register with udp portmap");
+ exit(1);
+ }
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't Add UDP socket");
+ exit(1);
+ }
+ (void)close(sock);
+ }
+
+#ifdef ISO
+ /* If we are serving cltp, set up the socket. */
+ if (cltpflag) {
+ if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create cltp socket");
+ exit(1);
+ }
+ memset(&isoaddr, 0, sizeof(isoaddr));
+ isoaddr.siso_family = AF_ISO;
+ isoaddr.siso_tlen = 2;
+ cp = TSEL(&isoaddr);
+ *cp++ = (NFS_PORT >> 8);
+ *cp = (NFS_PORT & 0xff);
+ isoaddr.siso_len = sizeof(isoaddr);
+ if (bind(sock,
+ (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind cltp addr");
+ exit(1);
+ }
+#ifdef notyet
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register with udp portmap");
+ exit(1);
+ }
+#endif /* notyet */
+ nfsdargs.sock = sock;
+ nfsdargs.name = NULL;
+ nfsdargs.namelen = 0;
+ if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
+ syslog(LOG_ERR, "can't add UDP socket");
+ exit(1);
+ }
+ close(sock);
+ }
+#endif /* ISO */
+
+ /* Now set up the master server socket waiting for tcp connections. */
+ on = 1;
+ FD_ZERO(&sockbits);
+ connect_type_cnt = 0;
+ if (tcpflag) {
+ if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tcp socket");
+ exit(1);
+ }
+ if (setsockopt(tcpsock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(tcpsock,
+ (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tcp addr");
+ exit(1);
+ }
+ if (listen(tcpsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tcpsock, &sockbits);
+ maxsock = tcpsock;
+ connect_type_cnt++;
+ }
+
+#ifdef notyet
+ /* Now set up the master server socket waiting for tp4 connections. */
+ if (tp4flag) {
+ if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tp4 socket");
+ exit(1);
+ }
+ if (setsockopt(tp4sock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ memset(&isoaddr, 0, sizeof(isoaddr));
+ isoaddr.siso_family = AF_ISO;
+ isoaddr.siso_tlen = 2;
+ cp = TSEL(&isoaddr);
+ *cp++ = (NFS_PORT >> 8);
+ *cp = (NFS_PORT & 0xff);
+ isoaddr.siso_len = sizeof(isoaddr);
+ if (bind(tp4sock,
+ (struct sockaddr *)&isoaddr, sizeof (isoaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tp4 addr");
+ exit(1);
+ }
+ if (listen(tp4sock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tp4sock, &sockbits);
+ maxsock = tp4sock;
+ connect_type_cnt++;
+ }
+
+ /* Now set up the master server socket waiting for tpip connections. */
+ if (tpipflag) {
+ if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
+ syslog(LOG_ERR, "can't create tpip socket");
+ exit(1);
+ }
+ if (setsockopt(tpipsock,
+ SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
+ inetaddr.sin_family = AF_INET;
+ inetaddr.sin_addr.s_addr = INADDR_ANY;
+ inetaddr.sin_port = htons(NFS_PORT);
+ inetaddr.sin_len = sizeof(inetaddr);
+ if (bind(tpipsock,
+ (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
+ syslog(LOG_ERR, "can't bind tcp addr");
+ exit(1);
+ }
+ if (listen(tpipsock, 5) < 0) {
+ syslog(LOG_ERR, "listen failed");
+ exit(1);
+ }
+ /*
+ * XXX
+ * Someday this should probably use "rpcbind", the son of
+ * portmap.
+ */
+ if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
+ syslog(LOG_ERR, "can't register tcp with portmap");
+ exit(1);
+ }
+ FD_SET(tpipsock, &sockbits);
+ maxsock = tpipsock;
+ connect_type_cnt++;
+ }
+#endif /* notyet */
+
+ if (connect_type_cnt == 0)
+ exit(0);
+
+ setproctitle("nfsd-master");
+
+ /*
+ * Loop forever accepting connections and passing the sockets
+ * into the kernel for the mounts.
+ */
+ for (;;) {
+ ready = sockbits;
+ if (connect_type_cnt > 1) {
+ if (select(maxsock + 1,
+ &ready, NULL, NULL, NULL) < 1) {
+ syslog(LOG_ERR, "select failed: %m");
+ exit(1);
+ }
+ }
+ if (tcpflag && FD_ISSET(tcpsock, &ready)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tcpsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ exit(1);
+ }
+ memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = sizeof(inetpeer);
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+#ifdef notyet
+ if (tp4flag && FD_ISSET(tp4sock, &ready)) {
+ len = sizeof(isopeer);
+ if ((msgsock = accept(tp4sock,
+ (struct sockaddr *)&isopeer, &len)) < 0) {
+ syslog(LOG_ERR, "accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR,
+ "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&isopeer;
+ nfsdargs.namelen = len;
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+ if (tpipflag && FD_ISSET(tpipsock, &ready)) {
+ len = sizeof(inetpeer);
+ if ((msgsock = accept(tpipsock,
+ (struct sockaddr *)&inetpeer, &len)) < 0) {
+ syslog(LOG_ERR, "Accept failed: %m");
+ exit(1);
+ }
+ if (setsockopt(msgsock, SOL_SOCKET,
+ SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
+ syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
+ nfsdargs.sock = msgsock;
+ nfsdargs.name = (caddr_t)&inetpeer;
+ nfsdargs.namelen = len;
+ nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
+ (void)close(msgsock);
+ }
+#endif /* notyet */
+ }
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "nfsd %s\n", USAGE);
+ exit(1);
+}
+
+void
+nonfs(signo)
+ int signo;
+{
+ syslog(LOG_ERR, "missing system call: NFS not available.");
+}
+
+void
+reapchild(signo)
+ int signo;
+{
+
+ while (wait3(NULL, WNOHANG, NULL));
+}
+
+void
+setproctitle(a)
+ char *a;
+{
+ register char *cp;
+ char buf[80];
+
+ cp = Argv[0];
+ (void)snprintf(buf, sizeof(buf), "%s", a);
+ (void)strncpy(cp, buf, LastArg - cp);
+ cp += strlen(cp);
+ while (cp < LastArg)
+ *cp++ = '\0';
+}
diff --git a/usr.sbin/nologin/Makefile b/usr.sbin/nologin/Makefile
new file mode 100644
index 0000000..5d89fff
--- /dev/null
+++ b/usr.sbin/nologin/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.2 (Berkeley) 4/22/94
+
+MAN8= nologin.8
+
+nologin clean depend lint tags:
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+ ${.CURDIR}/nologin.sh ${DESTDIR}/sbin/nologin
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/nologin/nologin.8 b/usr.sbin/nologin/nologin.8
new file mode 100644
index 0000000..32a7e73
--- /dev/null
+++ b/usr.sbin/nologin/nologin.8
@@ -0,0 +1,54 @@
+.\" 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.
+.\"
+.\" @(#)nologin.8 8.1 (Berkeley) 6/19/93
+.\"
+.Dd June 19, 1993
+.Dt NOLOGIN 8
+.Os BSD 4.4
+.Sh NAME
+.Nm nologin
+.Nd politely refuse a login
+.Sh SYNOPSIS
+.Nm nologin
+.Sh DESCRIPTION
+.Nm Nologin
+displays a message that an account is not available and
+exits non-zero.
+It is intended as a replacement shell field for accounts that
+have been disabled.
+.Sh SEE ALSO
+.Xr login 1
+.Sh HISTORY
+The
+.Nm nologin
+command appeared in
+.Bx 4.4 .
diff --git a/usr.sbin/nologin/nologin.sh b/usr.sbin/nologin/nologin.sh
new file mode 100644
index 0000000..8ad87fb
--- /dev/null
+++ b/usr.sbin/nologin/nologin.sh
@@ -0,0 +1,38 @@
+#!/bin/sh -
+#
+# 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.
+#
+# @(#)nologin.sh 8.1 (Berkeley) 6/5/93
+#
+
+echo 'This account is currently not available.'
+exit 1
diff --git a/usr.sbin/nslookup/Makefile b/usr.sbin/nslookup/Makefile
new file mode 100644
index 0000000..4295c99
--- /dev/null
+++ b/usr.sbin/nslookup/Makefile
@@ -0,0 +1,14 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= nslookup
+SRCS= main.c commands.l getinfo.c debug.c send.c skip.c list.c subr.c
+MAN8= nslookup.8
+DPADD+= ${LIBL}
+LDADD+= -ll
+CLEANFILES+=lex.yy.o
+
+beforeinstall:
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/nslookup.help \
+ ${DESTDIR}/usr/share/misc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/nslookup/commands.l b/usr.sbin/nslookup/commands.l
new file mode 100644
index 0000000..f70d1aa
--- /dev/null
+++ b/usr.sbin/nslookup/commands.l
@@ -0,0 +1,219 @@
+%{
+
+/*
+ * ++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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)commands.l 5.13 (Berkeley) 7/24/90";
+#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[];
+extern void PrintHelp();
+
+%}
+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}*$ {
+ 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/nslookup/debug.c b/usr.sbin/nslookup/debug.c
new file mode 100644
index 0000000..1d5383e
--- /dev/null
+++ b/usr.sbin/nslookup/debug.c
@@ -0,0 +1,541 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)debug.c 5.26 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: debug.c,v 1.1.1.1 1994/09/22 21:36:01 pst 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 <netiso/iso.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include "res.h"
+
+/*
+ * 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)
+ u_char *msg, *eom;
+ int printHeader;
+ FILE *file;
+{
+ register u_char *cp;
+ register HEADER *hp;
+ register int n;
+ short class;
+ short type;
+
+ /*
+ * Print header fields.
+ */
+ hp = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ 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((u_char*)cp);
+ cp += INT16SZ;
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ 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");
+}
+
+
+u_char *
+Print_cdname_sub(cp, msg, eom, file, format)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+ int format;
+{
+ int n;
+ char name[MAXDNAME];
+
+ n = dn_expand(msg, eom, cp, name, sizeof name);
+ if (n < 0)
+ return (NULL);
+ if (name[0] == '\0') {
+ (void) strcpy(name, "(root)");
+ }
+ if (format) {
+ fprintf(file, "%-30s", name);
+ } else {
+ fputs(name, file);
+ }
+ return (cp + n);
+}
+
+u_char *
+Print_cdname(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ return (Print_cdname_sub(cp, msg, eom, file, 0));
+}
+
+u_char *
+Print_cdname2(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ return (Print_cdname_sub(cp, msg, eom, file, 1));
+}
+
+/*
+ * Print resource record fields in human readable form.
+ */
+u_char *
+Print_rr(cp, msg, eom, file)
+ u_char *cp, *msg, *eom;
+ FILE *file;
+{
+ int type, class, dlen, n, c;
+ u_int32_t rrttl, ttl;
+ struct in_addr inaddr;
+ struct iso_addr isoa;
+ u_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((u_char*)cp);
+ cp += INT16SZ;
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ rrttl = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ 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, INADDRSZ);
+ 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((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", mail exchanger = ");
+ goto doname;
+ case T_RT:
+ fprintf(file,"\tpreference = %u",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", router = ");
+ goto doname;
+ case T_AFSDB:
+ fprintf(file,"\tsubtype = %d",_getshort((u_char*)cp));
+ cp += INT16SZ;
+ fprintf(file,", DCE/AFS server = ");
+ 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_ISDN:
+ if (n = *cp++) {
+ fprintf(file,"\tISDN = \"%.*s", n, cp);
+ cp += n;
+ }
+ if (n = *cp++) {
+ fprintf(file,"-%.*s\"\n", n, cp);
+ cp += n;
+ } else fprintf(file,"\"\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((u_char*)cp));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\trefresh = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\tretry = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,"\n\texpire = %lu (%s)", ttl, p_time(ttl));
+ cp += INT32SZ;
+ ttl = _getlong((u_char*)cp);
+ fprintf(file,
+ "\n\tminimum ttl = %lu (%s)\n", ttl, p_time(ttl));
+ cp += INT32SZ;
+ 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_RP:
+ if (!debug)
+ (void) putc('\n', file);
+ fprintf(file,"\tmailbox = ");
+ cp = Print_cdname(cp, msg, eom, file);
+ fprintf(file,"\n\ttext = ");
+ 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_X25:
+ (void) fputs("\tX25 = \"", 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_NSAP:
+ isoa.isoa_len = dlen;
+ if (isoa.isoa_len > sizeof(isoa.isoa_genaddr))
+ isoa.isoa_len = sizeof(isoa.isoa_genaddr);
+ bcopy(cp, isoa.isoa_genaddr, isoa.isoa_len);
+ fprintf(file, "\tnsap = %s\n", iso_ntoa(&isoa));
+ cp += dlen;
+ 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 = %u\n",type == T_UID ? 'u' : 'g',
+ _getlong((u_char*)cp));
+ cp += INT32SZ;
+ } 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 < INT32SZ + 1)
+ break;
+ if (!debug)
+ (void) putc('\n', file);
+ bcopy(cp, (char *)&inaddr, INADDRSZ);
+ cp += INT32SZ;
+ 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/nslookup/getinfo.c b/usr.sbin/nslookup/getinfo.c
new file mode 100644
index 0000000..7d86c2c
--- /dev/null
+++ b/usr.sbin/nslookup/getinfo.c
@@ -0,0 +1,827 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)getinfo.c 5.26 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: getinfo.c,v 1.1.1.1 1994/09/22 21:36:01 pst 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 <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;
+ u_char qb2[PACKETSZ*2];
+} querybuf;
+
+typedef union {
+ int32_t al;
+ char ac;
+} align;
+
+#define GetShort(cp) _getshort(cp); cp += INT16SZ;
+
+
+/*
+ ******************************************************************************
+ *
+ * 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 + HFIXEDSZ;
+
+ /* 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) {
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* 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.
+ */
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ cp += n;
+ continue;
+ }
+ cp += n;
+ len = strlen((char *)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((char *)bp) + 1;
+ hostPtr->name = Calloc(1, len);
+ bcopy(bp, hostPtr->name, len);
+ }
+ bp += (((u_int32_t)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.
+ */
+
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen((char *)bp) + 1;
+ dnamePtr = Calloc(1, len); /* domain name */
+ bcopy(bp, dnamePtr, len);
+
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_NS) {
+ cp += dlen;
+ } else {
+ Boolean found;
+
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ return(ERROR);
+ }
+ cp += n;
+ len = strlen((char *)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) {
+ n = dn_expand(answer.qb2, eom, cp, (char *)bp, buflen);
+ if (n < 0) {
+ break;
+ }
+ cp += n;
+ type = GetShort(cp);
+ class = GetShort(cp);
+ cp += INT32SZ; /* skip TTL */
+ dlen = GetShort(cp);
+
+ if (type != T_A) {
+ cp += dlen;
+ continue;
+ } else {
+ for (j = 0; j < numServers; j++) {
+ if (strcmp((char *)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 = INADDRSZ;
+ hostPtr->addrList = (char **)Calloc(2, sizeof(char *));
+ hostPtr->addrList[0] = Calloc(INT32SZ, sizeof(char));
+ bcopy((char *)&ina, hostPtr->addrList[0], INADDRSZ);
+ 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,
+ NULL, 0, 0, buf.qb2, 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 a PTR lookup in in-addr.arpa 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,
+ buf.qb2, 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(INT32SZ, sizeof(char));
+ bcopy((char *)p, hostPtr->addrList[0], INADDRSZ);
+ 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/nslookup/list.c b/usr.sbin/nslookup/list.c
new file mode 100644
index 0000000..6bafe19
--- /dev/null
+++ b/usr.sbin/nslookup/list.c
@@ -0,0 +1,997 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)list.c 5.23 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: list.c,v 1.1.1.1 1994/09/22 21:36:01 pst 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 <netiso/iso.h>
+#include <arpa/nameser.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include "res.h"
+
+extern char *_res_resultcodes[]; /* res_debug.c */
+extern char *pager;
+
+typedef union {
+ HEADER qb1;
+ u_char qb2[PACKETSZ];
+} querybuf;
+
+extern HostInfo *defaultPtr;
+extern HostInfo curHostInfo;
+extern int curHostValid;
+extern int queryType;
+extern int queryClass;
+
+static int sockFD = -1;
+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, stderr);
+ 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));
+}
+
+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;
+ u_char *cp, *nmp;
+ char dname[2][NAME_LEN];
+ char file[NAME_LEN];
+ static u_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,
+ NULL, 0, 0, buf.qb2, 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
+ */
+
+ __putshort(msglen, (u_char *)&len);
+
+ if (write(sockFD, (char *)&len, INT16SZ) != INT16SZ ||
+ 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_AFSDB:
+ fprintf(filePtr, " %-30s\n", "Subtype & Host");
+ break;
+ case T_X25:
+ fprintf(filePtr, " %-30s\n", "X25 Address");
+ break
+ case T_ISDN:
+ fprintf(filePtr, " %-30s\n", "ISDN Address");
+ 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_RP:
+ fprintf(filePtr, " %-30s\n", "Responsible Person");
+ break;
+ case T_RT:
+ fprintf(filePtr, " %-30s\n", "Router");
+ break;
+ case T_NSAP:
+ fprintf(filePtr, " %-30s\n", "NSAP address");
+ 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 = (u_char *)&tmp;
+ amtToRead = INT16SZ;
+ while ((numRead = read(sockFD, cp, amtToRead)) > 0) {
+ cp += numRead;
+ if ((amtToRead -= numRead) <= 0)
+ break;
+ }
+ if (numRead <= 0) {
+ error = ERR_READING_LEN;
+ break;
+ }
+
+ if ((len = _getshort((u_char*)&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 = (u_char *)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 + HFIXEDSZ;
+ 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((u_char*)cp) == T_SOA)) {
+ (void) dn_expand(answer, answer + len, nmp,
+ 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_int32_t ttl;
+ int n, pref;
+ struct in_addr inaddr;
+ struct iso_addr isoa;
+ char name[NAME_LEN];
+ char name2[NAME_LEN];
+ Boolean stripped;
+
+ /*
+ * Read the header fields.
+ */
+ headerPtr = (HEADER *)msg;
+ cp = msg + HFIXEDSZ;
+ 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;
+ }
+ nameLen = dn_expand(msg, eom, cp, name, sizeof name);
+ if (nameLen < 0)
+ return (ERROR);
+ cp += nameLen;
+
+ type = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ if (!(type == qtype || qtype == T_ANY) &&
+ !((type == T_NS || type == T_PTR) && qtype == T_A))
+ return(SUCCESS);
+
+ class = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ ttl = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ;
+
+ 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, INADDRSZ);
+ 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:
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 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:
+ case T_ISDN:
+ 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:
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s", name2);
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ cp += nameLen;
+ fprintf(file, " %s. (", name2);
+ for (n = 0; n < 5; n++) {
+ u_int32_t u;
+
+ u = _getlong((u_char*)cp);
+ cp += INT32SZ;
+ fprintf(file,"%s%lu", n? " " : "", u);
+ }
+ fprintf(file, ")");
+ break;
+
+ case T_MX:
+ case T_AFSDB:
+ case T_RT:
+ pref = _getshort((u_char*)cp);
+ cp += INT16SZ;
+ fprintf(file," %-3d ",pref);
+ nameLen = dn_expand(msg, eom, cp, name2, sizeof name2);
+ if (nameLen < 0) {
+ fprintf(file, " ***\n");
+ return (ERROR);
+ }
+ fprintf(file, " %s", name2);
+ break;
+
+ case T_TXT:
+ case T_X25:
+ {
+ 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_NSAP:
+ isoa.isoa_len = dlen;
+ if (isoa.isoa_len > sizeof(isoa.isoa_genaddr))
+ isoa.isoa_len = sizeof(isoa.isoa_genaddr);
+ bcopy(cp, isoa.isoa_genaddr, isoa.isoa_len);
+ fprintf(file, " %s", iso_ntoa(&isoa));
+ break;
+
+ case T_MINFO:
+ case T_RP:
+ (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((u_char*)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[PATH_MAX];
+ char command[PATH_MAX];
+
+ sscanf(string, " view %s", file);
+ (void)sprintf(command, "grep \"^ \" %s | sort | %s", file, pager);
+ 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");
+ lastc = '\n';
+ 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/nslookup/main.c b/usr.sbin/nslookup/main.c
new file mode 100644
index 0000000..5daeadf
--- /dev/null
+++ b/usr.sbin/nslookup/main.c
@@ -0,0 +1,1112 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#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[] = "@(#)main.c 5.42 (Berkeley) 3/3/91";
+static char rcsid[] = "$Id: main.c,v 1.1.1.1 1994/09/22 21:36:01 pst 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 <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h>
+#include "res.h"
+#include "pathnames.h"
+
+/*
+ * Name of a top-level name server. Can be changed with
+ * the "set root" command.
+ */
+
+#ifndef ROOT_SERVER
+#define ROOT_SERVER "ns.internic.net."
+#endif
+char rootServerName[NAME_LEN] = ROOT_SERVER;
+
+
+/*
+ * Import the state information from the resolver library.
+ */
+
+extern struct __res_state _res;
+
+
+/*
+ * 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;
+
+
+/*
+ * Browser command for help and view.
+ */
+char *pager;
+
+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;
+
+ /*
+ * 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)) {
+ _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 {
+ 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;
+ }
+ }
+ }
+
+
+ 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);
+
+ pager = getenv("PAGER");
+ if (pager == NULL) {
+ pager = _PATH_PAGERCMD;
+ }
+
+ /*
+ * 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];
+
+ (void) gethostname(hostName, sizeof(hostName));
+
+ 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);
+}
+
+
+/*
+ ******************************************************************************
+ *
+ * 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 != '.') {
+ return inet_aton(host, addrPtr);
+ }
+ }
+ 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[PATH_MAX];
+ 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[PATH_MAX];
+ 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, stderr);
+ }
+ } else if (strncmp(option, "cl", 2) == 0) { /* query class */
+ ptr = strchr(option, '=');
+ if (ptr != NULL) {
+ sscanf(++ptr, "%s", type);
+ queryClass = StringToClass(type, queryClass, stderr);
+ }
+ } 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 --
+ *
+ * Displays the help file.
+ *
+ ******************************************************************************
+ */
+
+void
+PrintHelp()
+{
+ char cmd[PATH_MAX];
+
+ sprintf(cmd, "%s %s", pager, _PATH_HELPFILE);
+ system(cmd);
+}
+
+/*
+ ******************************************************************************
+ *
+ * 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[PATH_MAX];
+
+ if ((cp = getenv("HOME")) != NULL) {
+ (void) strcpy(buf, cp);
+ (void) strcat(buf, _PATH_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/nslookup/nslookup.8 b/usr.sbin/nslookup/nslookup.8
new file mode 100644
index 0000000..de0306a
--- /dev/null
+++ b/usr.sbin/nslookup/nslookup.8
@@ -0,0 +1,387 @@
+.\"
+.\" ++Copyright++ 1985, 1989
+.\" -
+.\" Copyright (c) 1985, 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.
+.\" -
+.\" 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--
+.\"
+.\" @(#)nslookup.8 5.3 (Berkeley) 6/24/90
+.\"
+.TH NSLOOKUP @SYS_OPS_EXT_U@ "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.internic.net is used.
+(This command is a synonym for \fBlserver ns.internic.net.\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(@CMD_EXT@).
+.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.internic.net., 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(@LIB_NETWORK_EXT@), resolver(@FORMAT_EXT@), @INDOT@named(@SYS_OPS_EXT@),
+.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/nslookup/nslookup.help b/usr.sbin/nslookup/nslookup.help
new file mode 100644
index 0000000..2c17d4d
--- /dev/null
+++ b/usr.sbin/nslookup/nslookup.help
@@ -0,0 +1,33 @@
+$Id: nslookup.help,v 4.9.1.3 1993/12/06 00:43:17 vixie Exp $
+
+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,TXT,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/nslookup/pathnames.h b/usr.sbin/nslookup/pathnames.h
new file mode 100644
index 0000000..f2693b5
--- /dev/null
+++ b/usr.sbin/nslookup/pathnames.h
@@ -0,0 +1,66 @@
+/*
+ * ++Copyright++ 1990
+ * -
+ * 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.
+ * -
+ * 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--
+ */
+
+/*
+ * @(#)pathnames.h 5.1 (Berkeley) 5/28/90
+ * $Id: pathnames.h,v 4.9.1.3 1993/09/16 09:02:07 vixie Exp $
+ */
+
+#define _PATH_NSLOOKUPRC "/.nslookuprc"
+#define _PATH_PAGERCMD "more"
+
+#ifndef _PATH_HELPFILE
+#define _PATH_HELPFILE "/usr/share/misc/nslookup.help"
+#endif
diff --git a/usr.sbin/nslookup/res.h b/usr.sbin/nslookup/res.h
new file mode 100644
index 0000000..e86bc2f
--- /dev/null
+++ b/usr.sbin/nslookup/res.h
@@ -0,0 +1,172 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+/*
+ * @(#)res.h 5.10 (Berkeley) 6/1/90
+ * $Id: res.h,v 4.9.1.3 1994/06/01 21:10:16 vixie 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 unsigned char *Print_cdname();
+extern unsigned char *Print_cdname2(); /* fixed width */
+extern unsigned 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/nslookup/send.c b/usr.sbin/nslookup/send.c
new file mode 100644
index 0000000..6e793a5
--- /dev/null
+++ b/usr.sbin/nslookup/send.c
@@ -0,0 +1,411 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: send.c,v 1.1.1.1 1994/09/22 21:36:02 pst 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"
+
+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
+
+
+
+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;
+ 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];
+ 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;
+ 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++) {
+ 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;
+ if (_res.options & RES_DEBUG)
+ perror("socket (vc) failed");
+ continue;
+ }
+ if (connect(s, (struct sockaddr *)&sin,
+ sizeof(struct sockaddr)) < 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("connect failed");
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ }
+ /*
+ * Send length & message
+ */
+ __putshort(buflen, (u_char *)&len);
+ iov[0].iov_base = (caddr_t)&len;
+ iov[0].iov_len = INT16SZ;
+ iov[1].iov_base = buf;
+ iov[1].iov_len = buflen;
+ if (writev(s, iov, 2) != INT16SZ + buflen) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("write failed");
+ (void) close(s);
+ s = -1;
+ continue;
+ }
+ /*
+ * Receive length & response
+ */
+ cp = answer;
+ len = INT16SZ;
+ while ((n = read(s, (char *)cp, (int)len)) > 0) {
+ cp += n;
+ if ((len -= n) <= 0)
+ break;
+ }
+ if (n <= 0) {
+ terrno = errno;
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+ (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;
+ }
+ continue;
+ }
+ cp = answer;
+ if ((resplen = _getshort((u_char*)cp)) > anslen) {
+ if (_res.options & RES_DEBUG)
+ fprintf(stderr, "response truncated\n");
+ 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;
+ if (_res.options & RES_DEBUG)
+ perror("read failed");
+ (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;
+ if (_res.options & RES_DEBUG)
+ perror("socket (dg) failed");
+ continue;
+ }
+ }
+#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,
+ (struct sockaddr *) &sin,
+ sizeof(sin)) != buflen) {
+ if (_res.options & RES_DEBUG)
+ perror("sendto");
+ continue;
+ }
+#endif
+
+ /*
+ * Wait for reply
+ */
+ timeout.tv_sec = (_res.retrans << try);
+ 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) {
+ if (_res.options & RES_DEBUG)
+ perror("select");
+ continue;
+ }
+ if (n == 0) {
+ /*
+ * timeout
+ */
+ if (_res.options & RES_DEBUG)
+ printf("timeout (%d secs)\n",
+ timeout.tv_sec);
+#if BSD >= 43
+ gotsomewhere = 1;
+#endif
+ continue;
+ }
+ if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
+ if (_res.options & RES_DEBUG)
+ perror("recvfrom");
+ continue;
+ }
+ gotsomewhere = 1;
+ if (id != anhp->id) {
+ /*
+ * response from old query, ignore it
+ */
+ if (_res.options & RES_DEBUG2) {
+ printf("------------\nOld answer:\n");
+ Print_query(answer, answer+resplen, 1);
+ }
+ goto wait;
+ }
+ if (!(_res.options & RES_IGNTC) && anhp->tc) {
+ /*
+ * get rest of answer;
+ * use TCP with same server.
+ */
+ if (_res.options & RES_DEBUG)
+ printf("truncated answer\n");
+ (void) close(s);
+ s = -1;
+ v_circuit = 1;
+ goto usevc;
+ }
+ }
+ 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);
+ }
+ if (s >= 0) {
+ (void) close(s);
+ s = -1;
+ }
+ 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;
+}
+
+/*
+ * 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/nslookup/skip.c b/usr.sbin/nslookup/skip.c
new file mode 100644
index 0000000..7b5f889
--- /dev/null
+++ b/usr.sbin/nslookup/skip.c
@@ -0,0 +1,210 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)skip.c 5.12 (Berkeley) 3/21/91";
+static char rcsid[] = "$Id: skip.c,v 1.1.1.1 1994/09/22 21:36:02 pst 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 + HFIXEDSZ;
+
+ /*
+ * 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 += INT16SZ; /* type */
+ cp += INT16SZ; /* 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 += INT16SZ; /* type */
+ cp += INT16SZ; /* class */
+ cp += INT32SZ; /* ttl */
+ dlen = _getshort((u_char*)cp);
+ cp += INT16SZ; /* dlen */
+ cp += dlen;
+ if (cp > eom)
+ return (NULL);
+ return (cp);
+}
diff --git a/usr.sbin/nslookup/subr.c b/usr.sbin/nslookup/subr.c
new file mode 100644
index 0000000..0ad71f7
--- /dev/null
+++ b/usr.sbin/nslookup/subr.c
@@ -0,0 +1,559 @@
+/*
+ * ++Copyright++ 1985, 1989
+ * -
+ * Copyright (c) 1985, 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.
+ * -
+ * 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--
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)subr.c 5.24 (Berkeley) 3/2/91";
+static char rcsid[] = "$Id: subr.c,v 1.1.1.1 1994/09/22 21:36:02 pst 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 <string.h>
+#include <stdlib.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 && !defined(RISCOS_BSD)
+ 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 && !defined(RISCOS_BSD)
+ 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
+#if defined(SVR3) || defined(SVR4)
+ sighold(SIGINT);
+ ptr = malloc((unsigned) size);
+ sigrelse(SIGINT);
+#else
+ { void (*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 host/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, errorfile)
+ char *class;
+ int dflt;
+ FILE *errorfile;
+{
+ 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);
+ if (errorfile)
+ fprintf(errorfile, "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, errorfile)
+ char *type;
+ int dflt;
+ FILE *errorfile;
+{
+ 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 */
+ if (strcasecmp(type, "RP") == 0)
+ return(T_RP); /* responsible person */
+ if (strcasecmp(type, "X25") == 0)
+ return(T_X25); /* x25 address */
+ if (strcasecmp(type, "ISDN") == 0)
+ return(T_ISDN); /* isdn address */
+ if (strcasecmp(type, "RT") == 0)
+ return(T_RT); /* router */
+ if (strcasecmp(type, "AFSDB") == 0)
+ return(T_AFSDB); /* DCE or AFS server */
+ if (strcasecmp(type, "NSAP") == 0)
+ return(T_NSAP); /* NSAP address */
+ if (errorfile)
+ fprintf(errorfile, "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_RP:
+ return("responsible person");
+ case T_AFSDB:
+ return("DCE or AFS server");
+ case T_X25:
+ return("X25 address");
+ case T_ISDN:
+ return("ISDN address");
+ case T_RT:
+ return("router");
+ case T_NSAP:
+ return("nsap address");
+ 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/pkg_install/+COMMENT b/usr.sbin/pkg_install/+COMMENT
new file mode 100644
index 0000000..d29a496
--- /dev/null
+++ b/usr.sbin/pkg_install/+COMMENT
@@ -0,0 +1 @@
+Package install (source), version 0.5 \ No newline at end of file
diff --git a/usr.sbin/pkg_install/+CONTENTS b/usr.sbin/pkg_install/+CONTENTS
new file mode 100644
index 0000000..ff4d7d9
--- /dev/null
+++ b/usr.sbin/pkg_install/+CONTENTS
@@ -0,0 +1,2 @@
+@cwd /usr/ports
+pkg_install
diff --git a/usr.sbin/pkg_install/+DESC b/usr.sbin/pkg_install/+DESC
new file mode 100644
index 0000000..dd42917
--- /dev/null
+++ b/usr.sbin/pkg_install/+DESC
@@ -0,0 +1,5 @@
+This is the pkg_install suite of tools for doing maintainance of
+software "packages". More documentation is available in the man pages
+for each individual command.
+
+This is pkg_install version 0.5.
diff --git a/usr.sbin/pkg_install/Makefile b/usr.sbin/pkg_install/Makefile
new file mode 100644
index 0000000..37a1f05
--- /dev/null
+++ b/usr.sbin/pkg_install/Makefile
@@ -0,0 +1,3 @@
+SUBDIR=lib add create delete info
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/pkg_install/Makefile.inc b/usr.sbin/pkg_install/Makefile.inc
new file mode 100644
index 0000000..50332c0
--- /dev/null
+++ b/usr.sbin/pkg_install/Makefile.inc
@@ -0,0 +1,2 @@
+# Inherit BINDIR from one level up.
+.include "../Makefile.inc"
diff --git a/usr.sbin/pkg_install/README b/usr.sbin/pkg_install/README
new file mode 100644
index 0000000..dd42917
--- /dev/null
+++ b/usr.sbin/pkg_install/README
@@ -0,0 +1,5 @@
+This is the pkg_install suite of tools for doing maintainance of
+software "packages". More documentation is available in the man pages
+for each individual command.
+
+This is pkg_install version 0.5.
diff --git a/usr.sbin/pkg_install/add/Makefile b/usr.sbin/pkg_install/add/Makefile
new file mode 100644
index 0000000..2887d05
--- /dev/null
+++ b/usr.sbin/pkg_install/add/Makefile
@@ -0,0 +1,9 @@
+PROG= pkg_add
+
+CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib
+LDADD+= -L${.CURDIR}/../lib -L${.CURDIR}/../lib/obj -linstall
+
+
+SRCS= main.c perform.c futil.c extract.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg_install/add/add.h b/usr.sbin/pkg_install/add/add.h
new file mode 100644
index 0000000..019fc92
--- /dev/null
+++ b/usr.sbin/pkg_install/add/add.h
@@ -0,0 +1,43 @@
+/* $Id: add.h,v 1.4 1993/09/04 05:06:25 jkh Exp $ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Include and define various things wanted by the add command.
+ *
+ */
+
+#ifndef _INST_ADD_H_INCLUDE
+#define _INST_ADD_H_INCLUDE
+
+typedef enum { NORMAL, MASTER, SLAVE } add_mode_t;
+
+extern char *Prefix;
+extern Boolean NoInstall;
+extern Boolean NoRecord;
+extern char *Mode;
+extern char *Owner;
+extern char *Group;
+extern char *Directory;
+extern char *PkgName;
+extern char *PlayPen;
+extern add_mode_t AddMode;
+
+int make_hierarchy(char *);
+void extract_plist(char *, Package *);
+void apply_perms(char *, char *);
+
+#endif /* _INST_ADD_H_INCLUDE */
diff --git a/usr.sbin/pkg_install/add/extract.c b/usr.sbin/pkg_install/add/extract.c
new file mode 100644
index 0000000..d5db041
--- /dev/null
+++ b/usr.sbin/pkg_install/add/extract.c
@@ -0,0 +1,108 @@
+#ifndef lint
+static const char *rcsid = "$Id: extract.c,v 1.4 1993/09/06 23:26:21 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the package extraction code for the add module.
+ *
+ */
+
+#include "lib.h"
+#include "add.h"
+
+void
+extract_plist(char *home, Package *pkg)
+{
+ PackingList p = pkg->head;
+ char *last_file;
+
+ /* Reset the world */
+ Owner = NULL;
+ Group = NULL;
+ Mode = NULL;
+ last_file = NULL;
+ Directory = home;
+
+ /* Do it */
+ while (p) {
+ char cmd[FILENAME_MAX];
+
+ switch(p->type) {
+ case PLIST_NAME:
+ PkgName = p->name;
+ if (Verbose)
+ printf("extract: Package name is %s\n", p->name);
+ break;
+
+ case PLIST_FILE:
+ last_file = p->name;
+ if (Verbose)
+ printf("extract: %s/%s\n", Directory, p->name);
+ if (!Fake) {
+ char try[FILENAME_MAX];
+
+ /* first try to rename it into place */
+ sprintf(try, "%s/%s", Directory, p->name);
+ if (rename(p->name, try) == FAIL)
+ copy_hierarchy(Directory, p->name, TRUE);
+ apply_perms(Directory, p->name);
+ }
+ break;
+
+ case PLIST_CWD:
+ if (Verbose)
+ printf("extract: CWD to %s\n", p->name);
+ if (strcmp(p->name, ".")) {
+ if (!Fake && make_hierarchy(p->name) == FAIL)
+ barf("Unable make directory '%s'.", p->name);
+ Directory = p->name;
+ }
+ else
+ Directory = home;
+ break;
+
+ case PLIST_CMD:
+ format_cmd(cmd, p->name, Directory, last_file);
+ if (Verbose)
+ printf("extract: execute '%s'\n", cmd);
+ if (!Fake && system(cmd))
+ whinge("Command '%s' failed.", cmd);
+ break;
+
+ case PLIST_CHMOD:
+ Mode = p->name;
+ break;
+
+ case PLIST_CHOWN:
+ Owner = p->name;
+ break;
+
+ case PLIST_CHGRP:
+ Group = p->name;
+ break;
+
+ case PLIST_COMMENT:
+ break;
+
+ case PLIST_IGNORE:
+ p = p->next;
+ break;
+ }
+ p = p->next;
+ }
+}
diff --git a/usr.sbin/pkg_install/add/futil.c b/usr.sbin/pkg_install/add/futil.c
new file mode 100644
index 0000000..423f696
--- /dev/null
+++ b/usr.sbin/pkg_install/add/futil.c
@@ -0,0 +1,86 @@
+#ifndef lint
+static const char *rcsid = "$Id: futil.c,v 1.4 1993/09/04 05:06:27 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Miscellaneous file access utilities.
+ *
+ */
+
+#include "lib.h"
+#include "add.h"
+
+/*
+ * Assuming dir is a desired directory name, make it and all intervening
+ * directories necessary.
+ */
+
+int
+make_hierarchy(char *dir)
+{
+ char *cp1, *cp2;
+
+ if (dir[0] == '/')
+ cp1 = cp2 = dir + 1;
+ else
+ cp1 = cp2 = dir;
+ while (cp2) {
+ if ((cp2 = index(cp1, '/')) !=NULL )
+ *cp2 = '\0';
+ if (fexists(dir)) {
+ if (!isdir(dir))
+ return FAIL;
+ }
+ else {
+ if (vsystem("mkdir %s", dir))
+ return FAIL;
+ apply_perms(NULL, dir);
+ }
+ /* Put it back */
+ if (cp2) {
+ *cp2 = '/';
+ cp1 = cp2 + 1;
+ }
+ }
+ return SUCCESS;
+}
+
+/* Using permission defaults, apply them as necessary */
+void
+apply_perms(char *dir, char *file)
+{
+ char fname[FILENAME_MAX];
+
+ if (!dir || *file == '/') /* absolute path? */
+ strcpy(fname, file);
+ else
+ sprintf(fname, "%s/%s", dir, file);
+ if (Mode)
+ if (vsystem("chmod -R %s %s", Mode, fname))
+ whinge("Couldn't change mode of '%s' to '%s'.",
+ fname, Mode);
+ if (Owner)
+ if (vsystem("chown -R %s %s", Owner, fname))
+ whinge("Couldn't change owner of '%s' to '%s'.",
+ fname, Owner);
+ if (Group)
+ if (vsystem("chgrp -R %s %s", Group, fname))
+ whinge("Couldn't change group of '%s' to '%s'.",
+ fname, Group);
+}
+
diff --git a/usr.sbin/pkg_install/add/main.c b/usr.sbin/pkg_install/add/main.c
new file mode 100644
index 0000000..710fd70
--- /dev/null
+++ b/usr.sbin/pkg_install/add/main.c
@@ -0,0 +1,140 @@
+#ifndef lint
+static char *rcsid = "$Id: main.c,v 1.3 1993/09/05 04:53:49 jkh Exp $";
+#endif
+
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the add module.
+ *
+ */
+
+#include "lib.h"
+#include "add.h"
+
+static char Options[] = "hvIRnp:SMt:";
+
+char *Prefix = NULL;
+Boolean NoInstall = FALSE;
+Boolean NoRecord = FALSE;
+
+char *Mode = NULL;
+char *Owner = NULL;
+char *Group = NULL;
+char *PkgName = NULL;
+char *Directory = NULL;
+char *PlayPen = NULL;
+add_mode_t AddMode = NORMAL;
+
+int
+main(int argc, char **argv)
+{
+ int ch, err;
+ char **pkgs, **start;
+ char *prog_name = argv[0];
+
+ pkgs = start = argv;
+ while ((ch = getopt(argc, argv, Options)) != EOF)
+ switch(ch) {
+ case 'v':
+ Verbose = TRUE;
+ break;
+
+ case 'p':
+ Prefix = optarg;
+ break;
+
+ case 'I':
+ NoInstall = TRUE;
+ break;
+
+ case 'R':
+ NoRecord = TRUE;
+ break;
+
+ case 'n':
+ Fake = TRUE;
+ Verbose = TRUE;
+ break;
+
+ case 't':
+ PlayPen = optarg;
+ break;
+
+ case 'S':
+ AddMode = SLAVE;
+ break;
+
+ case 'M':
+ AddMode = MASTER;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage(prog_name, NULL);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* Get all the remaining package names, if any */
+ while (*argv)
+ *pkgs++ = *argv++;
+
+ /* If no packages, yelp */
+ *pkgs = NULL;
+ if (pkgs == start && AddMode != SLAVE)
+ usage(prog_name, "Missing package name(s)");
+ else if (start[1] && AddMode == MASTER)
+ usage(prog_name, "Only one package name may be specified with master mode");
+ else if (pkgs != start && AddMode == SLAVE)
+ whinge("Package names ignored in slave mode.");
+ if ((err = pkg_perform(start)) != NULL) {
+ if (Verbose)
+ fprintf(stderr, "%d package addition(s) failed.\n", err);
+ return err;
+ }
+ else
+ return 0;
+}
+
+void
+usage(const char *name, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (fmt) {
+ fprintf(stderr, "%s: ", name);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n\n");
+ }
+ va_end(args);
+ fprintf(stderr, "Usage: %s [args] pkg [ .. pkg ]\n", name);
+ fprintf(stderr, "Where args are one or more of:\n\n");
+ fprintf(stderr, "-v verbose\n");
+ fprintf(stderr, "-p arg override prefix with arg\n");
+ fprintf(stderr, "-I don't execute pkg install script, if any\n");
+ fprintf(stderr, "-R don't record installation (can't delete!)\n");
+ fprintf(stderr, "-n don't actually install, just show steps\n");
+ fprintf(stderr, "-t temp use temp as template for mktemp()\n");
+ fprintf(stderr, "-S run in SLAVE mode\n");
+ fprintf(stderr, "-M run in MASTER mode\n");
+ exit(1);
+}
diff --git a/usr.sbin/pkg_install/add/perform.c b/usr.sbin/pkg_install/add/perform.c
new file mode 100644
index 0000000..88719cd
--- /dev/null
+++ b/usr.sbin/pkg_install/add/perform.c
@@ -0,0 +1,235 @@
+#ifndef lint
+static const char *rcsid = "$Id: perform.c,v 1.7 1994/05/25 06:24:18 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the main body of the add module.
+ *
+ */
+
+#include "lib.h"
+#include "add.h"
+
+#include <signal.h>
+
+static int pkg_do(char *);
+static int sanity_check(char *);
+static char LogDir[FILENAME_MAX];
+
+
+int
+pkg_perform(char **pkgs)
+{
+ int i, err_cnt = 0;
+
+ signal(SIGINT, cleanup);
+ signal(SIGHUP, cleanup);
+
+ if (AddMode == SLAVE)
+ err_cnt = pkg_do(NULL);
+ else {
+ for (i = 0; pkgs[i]; i++)
+ err_cnt += pkg_do(pkgs[i]);
+ }
+ return err_cnt;
+}
+
+static Package Plist;
+
+/* This is seriously ugly code following. Written very fast! */
+static int
+pkg_do(char *pkg)
+{
+ char pkg_fullname[FILENAME_MAX];
+ FILE *cfile;
+ char *home;
+ int code = 0;
+ PackingList p;
+
+ /* Reset some state */
+ if (Plist.head)
+ free_plist(&Plist);
+ LogDir[0] = '\0';
+ if (AddMode == SLAVE) {
+ char tmp_dir[FILENAME_MAX];
+
+ fgets(tmp_dir, FILENAME_MAX, stdin);
+ tmp_dir[strlen(tmp_dir) - 1] = '\0'; /* pesky newline! */
+ if (chdir(tmp_dir) == FAIL) {
+ whinge("pkg_add in SLAVE mode can't chdir to %s.", tmp_dir);
+ return 1;
+ }
+ read_plist(&Plist, stdin);
+ }
+ else {
+ home = make_playpen(PlayPen);
+ if (pkg[0] == '/') /* full pathname? */
+ strcpy(pkg_fullname, pkg);
+ else
+ sprintf(pkg_fullname, "%s/%s", home, pkg);
+ if (!fexists(pkg_fullname)) {
+ whinge("Can't open package '%s'.", pkg_fullname);
+ return 1;
+ }
+
+ if (unpack(pkg_fullname, NULL))
+ return 1;
+
+ if (sanity_check(pkg_fullname))
+ return 1;
+
+ cfile = fopen(CONTENTS_FNAME, "r");
+ if (!cfile) {
+ whinge("Unable to open %s file.", CONTENTS_FNAME);
+ goto fail;
+ }
+ read_plist(&Plist, cfile);
+ fclose(cfile);
+ if (Prefix) {
+ /*
+ * If we have a prefix, delete the first one we see and add this
+ * one in place of it.
+ */
+ delete_plist(&Plist, FALSE, PLIST_CWD, NULL);
+ add_plist_top(&Plist, PLIST_CWD, Prefix);
+ }
+ /* If we're running in MASTER mode, just output the plist and return */
+ if (AddMode == MASTER) {
+ printf("%s\n", where_playpen());
+ write_plist(&Plist, stdout);
+ return 0;
+ }
+ }
+ setenv(PKG_PREFIX_VNAME,
+ (p = find_plist(&Plist, PLIST_CWD)) ? p->name : NULL, 1);
+ PkgName = (p = find_plist(&Plist, PLIST_NAME)) ? p->name : "anonymous";
+ if (fexists(REQUIRE_FNAME)) {
+ vsystem("chmod +x %s", REQUIRE_FNAME); /* be sure */
+ if (Verbose)
+ printf("Running requirements file first for %s..\n", PkgName);
+ if (!Fake && vsystem("./%s %s INSTALL", REQUIRE_FNAME, PkgName)) {
+ whinge("Package %s fails requirements - not installed.",
+ pkg_fullname);
+ return 1;
+ }
+ }
+ if (!NoInstall && fexists(INSTALL_FNAME)) {
+ vsystem("chmod +x %s", INSTALL_FNAME); /* make sure */
+ if (Verbose)
+ printf("Running install with PRE-INSTALL for %s..\n", PkgName);
+ if (!Fake && vsystem("./%s %s PRE-INSTALL", INSTALL_FNAME, PkgName)) {
+ whinge("Install script returned error status.");
+ goto fail;
+ }
+ }
+ extract_plist(home, &Plist);
+ if (!NoInstall && fexists(INSTALL_FNAME)) {
+ if (Verbose)
+ printf("Running install with POST-INSTALL for %s..\n", PkgName);
+ if (!Fake && vsystem("./%s %s POST-INSTALL", INSTALL_FNAME, PkgName)) {
+ whinge("Install script returned error status.");
+ goto fail;
+ }
+ }
+ if (!NoRecord && !Fake) {
+ char contents[FILENAME_MAX];
+ FILE *cfile;
+
+ if (getuid() != 0)
+ whinge("Not running as root - trying to record install anyway.");
+ if (!PkgName) {
+ whinge("No package name! Can't record package, sorry.");
+ code = 1;
+ goto success; /* well, partial anyway */
+ }
+ sprintf(LogDir, "%s/%s", LOG_DIR, PkgName);
+ if (Verbose)
+ printf("Attempting to record package into %s..\n", LogDir);
+ if (make_hierarchy(LogDir)) {
+ whinge("Can't record package into '%s', you're on your own!",
+ LogDir);
+ bzero(LogDir, FILENAME_MAX);
+ code = 1;
+ goto success; /* close enough for government work */
+ }
+ /* Make sure pkg_info can read the entry */
+ vsystem("chmod a+rx %s", LogDir);
+ if (fexists(DEINSTALL_FNAME))
+ copy_file(".", DEINSTALL_FNAME, LogDir);
+ if (fexists(REQUIRE_FNAME))
+ copy_file(".", REQUIRE_FNAME, LogDir);
+ sprintf(contents, "%s/%s", LogDir, CONTENTS_FNAME);
+ cfile = fopen(contents, "w");
+ if (!cfile) {
+ whinge("Can't open new contents file '%s'! Can't register pkg.",
+ contents);
+ goto success; /* can't log, but still keep pkg */
+ }
+ write_plist(&Plist, cfile);
+ fclose(cfile);
+ copy_file(".", DESC_FNAME, LogDir);
+ copy_file(".", COMMENT_FNAME, LogDir);
+ if (Verbose)
+ printf("Package %s registered in %s\n", PkgName, LogDir);
+ }
+ goto success;
+
+ fail:
+ /* Nuke the whole (installed) show */
+ if (!Fake)
+ delete_package(FALSE, &Plist);
+
+ success:
+ /* delete the packing list contents */
+ leave_playpen();
+
+ return code;
+}
+
+static int
+sanity_check(char *pkg)
+{
+ if (!fexists(CONTENTS_FNAME)) {
+ whinge("Package %s has no CONTENTS file!", pkg);
+ return 1;
+ }
+ if (!fexists(COMMENT_FNAME)) {
+ whinge("Package %s has no COMMENT file!", pkg);
+ return 1;
+ }
+ if (!fexists(DESC_FNAME)) {
+ whinge("Package %s has no DESC file!", pkg);
+ return 1;
+ }
+ return 0;
+}
+
+void
+cleanup(int signo)
+{
+ if (signo)
+ printf("Signal %d received, cleaning up..\n", signo);
+ if (Plist.head) {
+ if (!Fake)
+ delete_package(FALSE, &Plist);
+ free_plist(&Plist);
+ }
+ if (!Fake && LogDir[0])
+ vsystem("%s -rf %s", REMOVE_CMD, LogDir);
+ leave_playpen();
+}
diff --git a/usr.sbin/pkg_install/add/pkg_add.1 b/usr.sbin/pkg_install/add/pkg_add.1
new file mode 100644
index 0000000..1863144
--- /dev/null
+++ b/usr.sbin/pkg_install/add/pkg_add.1
@@ -0,0 +1,203 @@
+.\"
+.\" FreeBSD install - a package for the installation and maintainance
+.\" of non-core utilities.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" Jordan K. Hubbard
+.\"
+.\"
+.\" @(#)pkg_add.1
+.\"
+.TH pkg_add 1 "July 18, 1993" "" "FreeBSD"
+
+.SH NAME
+pkg_add - a utility for installing software package distributions.
+.SH SYNOPSIS
+.na
+.B pkg_add
+.RB [options]
+.RB "pkg-name\ [.. pkg-name]"
+
+.SH DESCRIPTION
+The
+.B pkg_add
+command is used to extract packages that have been previously created
+with the
+.B pkg_create
+command.
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-v
+Turns on verbose output.
+.B "Optional."
+.TP
+.B \-I
+If an installation script exists for a given package, do not execute it.
+.B "Optional."
+.TP
+.B \-n
+Don't actually install a package, just report the steps that
+would be taken if it was.
+.B "Optional."
+.TP
+.B \-R
+Do not record the installation of a package. This means
+that you cannot deinstall it later, so only use this option if
+you know what you are doing!
+.B "Optional."
+.TP
+.BI "\-p\ " prefix
+Sets
+.I prefix
+as the directory in which to extract files from a package.
+If a package has set its default directory, it will be overridden
+by this flag. Note that only the first directory default will
+be replaced, since
+.B pkg_add
+has no way of knowing which directory settings are relative and
+which are absolute. It is rare, in any case, that more than one
+directory transition is made, but when such is the case then you
+may wish to look into the use of
+.B MASTER
+and
+.B SLAVE
+mode (see
+.B \-M
+and
+.B \-S
+options).
+.B "Optional."
+.TP
+.BI "\-t\ " template
+Use
+.I template
+as the input to mktemp(3). By default, this is the string
+.B /tmp/instmp.XXXXXX
+, but it may be necessary to override it in the situation where
+space in your
+.B /tmp
+directory is limited. Be sure to leave some number of `X' characters
+for mktemp(3) to fill in with a unique ID.
+.B "Optional."
+.TP
+.B \-M
+Run in
+.B MASTER
+mode. This is a very specialized mode for running
+.B pkg_add
+and is meant to be run in conjunction with
+.B SLAVE
+mode. When run in this mode,
+.B pkg_add
+does no work beyond extracting the package into a temporary staging
+area (see
+.B \-t
+option), reading in the packing list, and then dumping it (prefaced by
+the current staging area) to stdout where it may be filtered by a
+program such as
+.B sed(1).
+When used in conjunction with
+.B SLAVE
+mode, it allows you to make radical changes to the package structure
+before acting on its contents.
+.TP
+.B \-S
+Run in
+.B SLAVE
+mode. This is a very specialized mode for running
+.B pkg_add
+and is meant to be run in conjunction with
+.B MASTER
+mode. When run in this mode,
+.B pkg_add
+expects the release contents to be already extracted and waiting
+in the staging area, the location of which is read as a string
+from stdin. The complete packing list is also read from stdin,
+and the contents then acted on as normal.
+.PP
+.SH "TECHNICAL DETAILS"
+.B
+pkg_add
+is fairly simple. It simply extracts the requested packages into
+a "staging area" directory and then performs the following steps:
+.PP
+If the package contains a
+.B require
+file (see
+.B pkg_create
+), then this is executed first with the flags
+.PP
+.B <script>
+.I pkg-name INSTALL
+.PP
+to see whether or not installation should
+continue (a non-zero exit status means no).
+.PP
+If an
+.B install
+script exists for the package, it is then executed as follows:
+.PP
+First, before installing files in the data set, the
+.B install
+script is called with the flags
+.PP
+.B <script>
+.I pkg-name PRE-INSTALL
+.PP
+Where
+.I pkg-name
+is the name of the package in question and
+.I PRE-INSTALL
+is a keyword denoting that this is the "pre installation" pass.
+Using the packing list as a guide, files are then moved (or copied,
+as necessary) from the staging area into their new homes and the
+.B install
+script is then executed a second time with the flags
+.PP
+.B <script>
+.I pkg-name POST-INSTALL
+.PP
+This all allows you to write an
+.B install
+script that does "before and after" actions.
+.PP
+All the scripts are called with the environment variable
+.B PKG_PREFIX
+set to the installation prefix (see the
+.B -p
+option above). This allows a package author to write a script
+that reliably performs some action on the directory where the package
+is installed, even if the user might change it by
+.B -p
+when
+.B pkg_add
+is run.
+.PP
+After installation is complete, a copy of the packing list, in addition
+to any
+.B deinstall
+script the package might have, is copied into /var/db/pkg/<pkg-name>
+for subsequent possible use by
+.B pkg-delete.
+Finally, the staging area is deleted and the program terminates.
+.PP
+.SH BUGS
+Sure to be some.
+.SH "SEE ALSO"
+.BR pkg_create "(" 1 "),"
+.BR pkg_info "(" 1 "),"
+.BR pkg_delete "(" 1 "),"
+.SH AUTHORS
+Jordan Hubbard
+
diff --git a/usr.sbin/pkg_install/create/Makefile b/usr.sbin/pkg_install/create/Makefile
new file mode 100644
index 0000000..2f52910
--- /dev/null
+++ b/usr.sbin/pkg_install/create/Makefile
@@ -0,0 +1,9 @@
+PROG= pkg_create
+
+CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib
+LDADD+= -L${.CURDIR}/../lib -L${.CURDIR}/../lib/obj -linstall
+
+
+SRCS= main.c perform.c pl.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg_install/create/create.h b/usr.sbin/pkg_install/create/create.h
new file mode 100644
index 0000000..d45c177
--- /dev/null
+++ b/usr.sbin/pkg_install/create/create.h
@@ -0,0 +1,42 @@
+/* $Id: create.h,v 1.4 1993/09/12 20:45:28 jkh Exp $ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Include and define various things wanted by the create command.
+ *
+ */
+
+#ifndef _INST_CREATE_H_INCLUDE
+#define _INST_CREATE_H_INCLUDE
+
+extern char *Prefix;
+extern char *Comment;
+extern char *Desc;
+extern char *Install;
+extern char *DeInstall;
+extern char *Contents;
+extern char *Require;
+extern char *PlayPen;
+extern char *ExcludeFrom;
+extern int Dereference;
+
+void check_list(char *, Package *);
+void usage(const char *, const char *, ...);
+int pkg_perform(char **);
+void copy_plist(char *, Package *);
+
+#endif /* _INST_CREATE_H_INCLUDE */
diff --git a/usr.sbin/pkg_install/create/main.c b/usr.sbin/pkg_install/create/main.c
new file mode 100644
index 0000000..e7805ca
--- /dev/null
+++ b/usr.sbin/pkg_install/create/main.c
@@ -0,0 +1,150 @@
+#ifndef lint
+static const char *rcsid = "$Id: main.c,v 1.6 1994/04/16 21:50:53 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the create module.
+ *
+ */
+
+#include "lib.h"
+#include "create.h"
+
+static char Options[] = "YNhvf:p:c:d:i:k:r:t:X:";
+
+char *Prefix = NULL;
+char *Comment = NULL;
+char *Desc = NULL;
+char *Install = NULL;
+char *DeInstall = NULL;
+char *Contents = NULL;
+char *Require = NULL;
+char *PlayPen = NULL;
+char *ExcludeFrom = NULL;
+int Dereference = 0;
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ char **pkgs, **start;
+ char *prog_name = argv[0];
+
+ pkgs = start = argv;
+ while ((ch = getopt(argc, argv, Options)) != EOF)
+ switch(ch) {
+ case 'v':
+ Verbose = TRUE;
+ break;
+
+ case 'N':
+ AutoAnswer = NO;
+ break;
+
+ case 'Y':
+ AutoAnswer = YES;
+ break;
+
+ case 'p':
+ Prefix = optarg;
+ break;
+
+ case 'f':
+ Contents = optarg;
+ break;
+
+ case 'c':
+ Comment = optarg;
+ break;
+
+ case 'd':
+ Desc = optarg;
+ break;
+
+ case 'i':
+ Install = optarg;
+ break;
+
+ case 'k':
+ DeInstall = optarg;
+ break;
+
+ case 'r':
+ Require = optarg;
+ break;
+
+ case 't':
+ PlayPen = optarg;
+ break;
+
+ case 'X':
+ ExcludeFrom = optarg;
+ break;
+
+ case 'h':
+ Dereference = 1;
+ break;
+
+ case '?':
+ default:
+ usage(prog_name, NULL);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* Get all the remaining package names, if any */
+ while (*argv)
+ *pkgs++ = *argv++;
+
+ /* If no packages, yelp */
+ if (pkgs == start)
+ usage(prog_name, "Missing package name");
+ *pkgs = NULL;
+ if (start[1])
+ usage(prog_name, "Only one package name allowed\n\t('%s' extraneous)",
+ start[1]);
+ if (!pkg_perform(start)) {
+ if (Verbose)
+ fprintf(stderr, "Package creation failed.\n");
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void
+usage(const char *name, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (fmt) {
+ fprintf(stderr, "%s: ", name);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n\n");
+ }
+ va_end(args);
+ fprintf(stderr, "Usage: %s [args] pkg\n\n", name);
+ fprintf(stderr, "Where args are one or more of:\n\n");
+
+ fprintf(stderr, "-c [-]file Get one-line comment from file (-or arg)\n");
+ fprintf(stderr, "-d [-]file Get description from file (-or arg)\n");
+ fprintf(stderr, "-f file get list of files from file (- for stdin)\n");
+ fprintf(stderr, "-h follow symbolic links\n");
+ fprintf(stderr, "-i script install script\n");
+ fprintf(stderr, "-p arg install prefix will be arg\n");
+ fprintf(stderr, "-k script de-install script\n");
+ fprintf(stderr, "-r script pre/post requirements script\n");
+ fprintf(stderr, "-t temp use temp as template for mktemp()\n");
+ fprintf(stderr, "-X file exclude files listed in file\n");
+ fprintf(stderr, "-v verbose\n");
+ exit(1);
+}
diff --git a/usr.sbin/pkg_install/create/perform.c b/usr.sbin/pkg_install/create/perform.c
new file mode 100644
index 0000000..2f2bb5a
--- /dev/null
+++ b/usr.sbin/pkg_install/create/perform.c
@@ -0,0 +1,181 @@
+#ifndef lint
+static const char *rcsid = "$Id: perform.c,v 1.9 1994/05/25 06:24:41 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the main body of the create module.
+ *
+ */
+
+#include "lib.h"
+#include "create.h"
+
+#include <signal.h>
+
+static void sanity_check(void);
+static void make_dist(char *, char *, char *, Package *);
+
+int
+pkg_perform(char **pkgs)
+{
+ char *pkg = *pkgs; /* Only one arg to create */
+ char *home, *cp;
+ FILE *pkg_in, *fp;
+ Package plist;
+ char *suffix; /* What we tack on to the end of the finished package */
+
+ /* Preliminary setup */
+ sanity_check();
+ if (Verbose)
+ printf("Creating package %s\n", pkg);
+ get_dash_string(&Comment);
+ get_dash_string(&Desc);
+ if (!strcmp(Contents, "-"))
+ pkg_in = stdin;
+ else {
+ pkg_in = fopen(Contents, "r");
+ if (!pkg_in)
+ barf("Unable to open contents file '%s' for input.", Contents);
+ }
+ plist.head = plist.tail = NULL;
+
+ /* Break the package name into base and desired suffix (if any) */
+ if ((cp = rindex(pkg, '.')) != NULL) {
+ suffix = cp + 1;
+ *cp = '\0';
+ }
+ else
+ suffix = "tgz";
+
+ if (Prefix)
+ add_plist(&plist, PLIST_CWD, Prefix);
+
+ /* Slurp in the packing list */
+ read_plist(&plist, pkg_in);
+
+ /*
+ * Run down the list and see if we've named it, if not stick in a name
+ * at the top.
+ */
+ if (find_plist(&plist, PLIST_NAME) == NULL)
+ add_plist_top(&plist, PLIST_NAME, pkg);
+
+ /* Make a directory to stomp around in */
+ home = make_playpen(PlayPen);
+ signal(SIGINT, cleanup);
+ signal(SIGHUP, cleanup);
+
+ /* Make first "real contents" pass over it */
+ check_list(home, &plist);
+ copy_plist(home, &plist);
+ mark_plist(&plist);
+
+ /* Now put the release specific items in */
+ add_plist(&plist, PLIST_CWD, ".");
+ write_file(COMMENT_FNAME, Comment);
+ add_plist(&plist, PLIST_IGNORE, NULL);
+ add_plist(&plist, PLIST_FILE, COMMENT_FNAME);
+ write_file(DESC_FNAME, Desc);
+ add_plist(&plist, PLIST_IGNORE, NULL);
+ add_plist(&plist, PLIST_FILE, DESC_FNAME);
+
+ if (Install) {
+ copy_file(home, Install, INSTALL_FNAME);
+ add_plist(&plist, PLIST_IGNORE, NULL);
+ add_plist(&plist, PLIST_FILE, INSTALL_FNAME);
+ }
+ if (DeInstall) {
+ copy_file(home, DeInstall, DEINSTALL_FNAME);
+ add_plist(&plist, PLIST_IGNORE, NULL);
+ add_plist(&plist, PLIST_FILE, DEINSTALL_FNAME);
+ }
+ if (Require) {
+ copy_file(home, Require, REQUIRE_FNAME);
+ add_plist(&plist, PLIST_IGNORE, NULL);
+ add_plist(&plist, PLIST_FILE, REQUIRE_FNAME);
+ }
+
+ /* Run through the list again, picking up extra "local" items */
+ check_list(".", &plist);
+ copy_plist(".", &plist);
+ mark_plist(&plist);
+
+ /* Finally, write out the packing list */
+ fp = fopen(CONTENTS_FNAME, "w");
+ if (!fp)
+ barf("Can't open file %s for writing.", CONTENTS_FNAME);
+ write_plist(&plist, fp);
+ if (fclose(fp))
+ barf("Error while closing %s.", CONTENTS_FNAME);
+
+ /* And stick it into a tar ball */
+ make_dist(home, pkg, suffix, &plist);
+
+ /* Cleanup */
+ free(Comment);
+ free(Desc);
+ free_plist(&plist);
+ cleanup(0);
+ return TRUE; /* Success */
+}
+
+static void
+make_dist(char *home, char *pkg, char *suffix, Package *plist)
+{
+ char tball[FILENAME_MAX];
+ char args[10];
+ int ret;
+
+ args[0] = '\0';
+ if (*pkg == '/')
+ sprintf(tball, "%s.%s", pkg, suffix);
+ else
+ sprintf(tball, "%s/%s.%s", home, pkg, suffix);
+ if (index(suffix, 'z')) /* Compress/gzip? */
+ strcat(args, "z");
+ if (Dereference)
+ strcat(args, "h");
+ if (Verbose)
+ printf("Creating gzip'd tar ball in '%s'\n", tball);
+ strcat(args, "cf");
+ if (ExcludeFrom)
+ ret = vsystem("tar %sX %s %s .", args, tball, ExcludeFrom);
+ else
+ ret = vsystem("tar %s %s .", args, tball);
+ if (ret)
+ barf("tar command failed with code %d", ret);
+}
+
+static void
+sanity_check()
+{
+ if (!Comment)
+ barf("Required package comment string is missing (-c comment).");
+ if (!Desc)
+ barf("Required package description string is missing (-d desc).");
+ if (!Contents)
+ barf("Required package contents list is missing (-f [-]file).");
+}
+
+
+/* Clean up those things that would otherwise hang around */
+void
+cleanup(int sig)
+{
+ leave_playpen();
+}
diff --git a/usr.sbin/pkg_install/create/pkg_create.1 b/usr.sbin/pkg_install/create/pkg_create.1
new file mode 100644
index 0000000..c11eae4
--- /dev/null
+++ b/usr.sbin/pkg_install/create/pkg_create.1
@@ -0,0 +1,280 @@
+.\"
+.\" FreeBSD install - a package for the installation and maintainance
+.\" of non-core utilities.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" Jordan K. Hubbard
+.\"
+.\"
+.\" @(#)pkg_create.1
+.\"
+.TH pkg_create 1 "July 18, 1993" "" "FreeBSD"
+
+.SH NAME
+pkg_create - a utility for creating software package distributions.
+.SH SYNOPSIS
+.na
+.B pkg_create
+.RB [options]
+.RB pkg-name
+
+.SH DESCRIPTION
+The
+.B pkg_create
+command is used to create packages that will subsequently be fed to
+one of the package extraction/info utilities. The input description
+and command line arguments for the creation of a package are not
+really meant to be human-generated, though it is easy enough to
+do so. It is more expected that you will use a front-end tool for
+the job rather than muddling through it yourself. Nonetheless, a short
+description of the input syntax is included in this document.
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-Y
+Assume a default answer of `Yes' for any questions asked.
+.B "Optional."
+.TP
+.B \-N
+Assume a default answer of `No' for any questions asked.
+.B "Optional."
+.TP
+.B \-v
+Turns on verbose output.
+.B "Optional."
+.TP
+.BI "\-c\ " [-]desc
+Fetch package "one line description" from file
+.I desc
+or, if preceeded by
+.B -
+, the argument itself. This string should also
+give some idea of which version of the product (if any) the package
+represents.
+.B "Mandatory."
+.TP
+.BI "\-d\ " [-]desc
+Fetch long description for package from file
+.I desc
+or, if preceeded by
+.B -
+, the argument itself.
+.B "Mandatory."
+.TP
+.BI "\-f\ " file
+Fetch "packing list" for package from
+.I file
+or
+.B stdin
+if
+.I file
+is a
+.B -
+(dash).
+.B "Mandatory."
+.TP
+.B -h
+Forces tar to follow symbolic links, so that the files they point to
+are dumped, rather than the links themselves.
+.TP
+.BI "\-i\ " script
+Sets
+.I script
+to be the install procedure for the package. This can be any
+executable program (or shell script). It will be invoked automatically
+when the package is later installed.
+.B "Optional."
+.TP
+.BI "\-p\ " prefix
+Sets
+.I prefix
+As the initial directory "base" to start from in selecting files for
+the package.
+.B "Optional."
+.TP
+.BI "\-k\ " script
+Sets
+.I script
+to be the de-install procedure for the package. This can be any
+executable program (or shell script). It will be invoked automatically
+when the package is later (if ever) de-installed.
+.B "Optional."
+.TP
+.BI "\-r\ " script
+Sets
+.I script
+to be the "requirements" procedure for the package. This can be any
+executable program (or shell script). It will be invoked automatically
+at installation/deinstallation time to determine whether or not
+installation/deinstallation should proceed.
+.B "Optional."
+.TP
+.BI "\-t\ " template
+Use
+.I template
+as the input to mktemp(3). By default, this is the string
+.B /tmp/instmp.XXXXXX,
+but it may be necessary to override it in the situation where
+space in your
+.B /tmp
+directory is limited. Be sure to leave some number of `X' characters
+for mktemp(3) to fill in with a unique ID.
+.B "Optional."
+.TP
+.BI "\-X\ " file
+Pass
+.I file
+as a
+.B \-exclude-from
+argument to
+.B tar
+when creating final package. See
+.B tar
+man page (or run
+.B tar
+with
+.B --help
+flag) for further information on using this flag.
+.PP
+.SH "TECHNICAL DETAILS"
+The "packing list" format (see \fB-f\fR) is fairly simple, being
+nothing more than a single column of filenames to include in the
+package. However, since absolute pathnames are generally a bad idea
+for a package that could be installed potentially anywhere, there is
+another method of specifying where things are supposed to go
+and, optionally, what ownership and mode information they should be
+installed with. This is done by imbeding specialized command sequences
+in the packing list. Briefly described, these sequences are:
+.TP
+.BI "@cwd\ " directory
+Sets the internal directory pointer to point to
+.I directory.
+All subsequent filenames will be assumed relative to this directory.
+Note:
+.BI @cd
+is also an alias for this command.
+.TP
+.BI "@srcdir\ " directory
+Sets the internal directory pointer for _creation only_ to
+.I directory.
+That is to say that it overrides
+.I @cwd
+for package creation but not extraction.
+.TP
+.BI "@exec\ " command
+Execute
+.I command
+as part of the unpacking process. If
+.I command
+contains a any of the following sequences somewhere in it, they will
+be expanded inline. For the following examples, assume that
+.B @cwd
+is set to
+.B /usr/local
+and the last extracted file was
+.B bin/emacs.
+.TP
+.I "%F"
+Expands to the last filename extracted (as specified), in the example case
+.B bin/emacs
+.TP
+.I "%D"
+Expands to the current directory prefix, as set with
+.B @cwd,
+in the example case
+.B /usr/local.
+.TP
+.I "%B"
+Expands to the "basename" of the fully qualified filename, that
+is the current directory prefix, plus the last filespec, minus
+the trailing filename. In the example case, that would be
+.B /usr/local/bin.
+.TP
+.I "%f"
+Expands to the "filename" part of the fully qualified name, or
+the converse of
+.B %B
+, being in the example case,
+.B emacs.
+.TP
+.BI "@unexec\ " command
+Execute
+.I command
+as part of the deinstallation process. Expansion of special
+.B %
+sequences is the same as for
+.B @exec.
+This command is not executed during the package add, as
+.B @exec
+is, but rather when the package is deleted. This is useful
+for creating links and other ancillary files that were created
+as a result of adding the package, but not directly known to
+the package's table of contents (and hence not automatically
+removable). The advantage of using
+.B @unexec
+over a deinstallation script is that you can use the "special
+sequence expansion" to get at files regardless of where they've
+been potentially redirected (see
+.B -p)
+.TP
+.BI "@mode\ " mode
+Sets default permission for all subsequently extracted files to
+.I mode.
+Format is the same as that used by the
+.B chmod
+command (well, considering that it's later handed off to it, that's
+no surprise). Use without an arg to set back to default (extraction)
+permissions.
+.TP
+.BI "@owner\ " user
+Sets default ownership for all subsequently extracted files to
+.I user.
+Use without an arg to set back to default (extraction)
+ownership.
+.TP
+.BI "@group\ " group
+Sets default group ownership for all subsequently extracted files to
+.I group.
+Use without an arg to set back to default (extraction)
+group ownership.
+.TP
+.BI "@comment\ " string
+Imbed a comment in the packing list. Useful in
+trying to document some particularly hairy sequence that
+may trip someone up later.
+.TP
+.BI "@ignore\ " file
+Used internally to tell extraction to ignore the next file (don't
+copy it anywhere), as it's used for some special purpose. Also useful
+if you want to pack some specialized datafiles in with a distribution
+for your install script (or something) and want to have the installer
+ignore it.
+.TP
+.BI "@name\ " name
+Sets the name of the package. This is mandatory and is usually
+put at the top. This name is potentially different than the name of
+the file it came in, and is used when keeping track of the package
+for later deinstallation. Note that
+.B pkg_create
+will derive this field from the package name and add it automatically
+if none is given.
+
+.SH BUGS
+Sure to be some.
+.SH "SEE ALSO"
+.BR pkg_add "(" 1 "),"
+.BR pkg_info "(" 1 "),"
+.BR pkg_delete "(" 1 "),"
+.SH AUTHORS
+Jordan Hubbard
+
diff --git a/usr.sbin/pkg_install/create/pl.c b/usr.sbin/pkg_install/create/pl.c
new file mode 100644
index 0000000..a76da6a
--- /dev/null
+++ b/usr.sbin/pkg_install/create/pl.c
@@ -0,0 +1,111 @@
+#ifndef lint
+static const char *rcsid = "$Id: pl.c,v 1.3 1994/08/28 14:15:23 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Routines for dealing with the packing list.
+ *
+ */
+
+#include "lib.h"
+#include "create.h"
+
+#define QUERY_GZIP \
+"File '%s' appears to be gzip'd.\nWould you like to unpack it first"
+#define UNZIP "gzip -d %s"
+
+#define QUERY_COMPRESS \
+"File '%s' appears to be compressed.\nWould you like to unpack it first"
+#define UNCOMPRESS "compress -d %s"
+
+/* Check a list for files that require preconversion */
+void
+check_list(char *home, Package *pkg)
+{
+ char cmd[FILENAME_MAX];
+ char name[FILENAME_MAX];
+ char *where = home;
+ char *there = NULL;
+ PackingList p = pkg->head;
+
+ while (p) {
+ if (p->type == PLIST_CWD)
+ where = p->name;
+ else if (p->type == PLIST_IGNORE)
+ p = p->next;
+ else if (p->type == PLIST_SRC) {
+ there = p->name;
+ }
+ else if (p->type == PLIST_FILE) {
+ cmd[0] = '\0';
+ sprintf(name, "%s/%s", there ? there : where, p->name);
+ /* gzip? */
+ if ((suffix(name, "gz") || suffix(name, "z")) &&
+ y_or_n(TRUE, QUERY_GZIP, name))
+ sprintf(cmd, UNZIP, name);
+
+ /* Compress? */
+ else if (suffix(name, "Z") && y_or_n(TRUE, QUERY_COMPRESS, name))
+ sprintf(cmd, UNCOMPRESS, name);
+
+ if (*cmd) {
+ if (Verbose)
+ printf("Uncompressing-> %s\n", cmd);
+ if (system(cmd))
+ barf("%s failed!", cmd);
+ nuke_suffix(p->name);
+ }
+ }
+ p = p->next;
+ }
+}
+
+/*
+ * Copy unmarked files in packing list to playpen - marked files
+ * have already been copied in an earlier pass through the list.
+ */
+void
+copy_plist(char *home, Package *plist)
+{
+ PackingList p = plist->head;
+ char *where = home;
+ char *there = NULL;
+
+ while (p) {
+ if (p->type == PLIST_CWD)
+ where = p->name;
+ else if (p->type == PLIST_SRC)
+ there = p->name;
+ else if (p->type == PLIST_IGNORE)
+ p = p->next;
+ else if (p->type == PLIST_FILE && !p->marked) {
+ char fn[FILENAME_MAX];
+
+ /* First, look for it in the "home" dir */
+ sprintf(fn, "%s/%s", home, p->name);
+ if (fexists(fn))
+ copy_hierarchy(home, p->name, FALSE);
+ /*
+ * Otherwise, try along the actual extraction path..
+ */
+ else
+ copy_hierarchy(there ? there : where, p->name, FALSE);
+ }
+ p = p->next;
+ }
+}
diff --git a/usr.sbin/pkg_install/delete/Makefile b/usr.sbin/pkg_install/delete/Makefile
new file mode 100644
index 0000000..942f524
--- /dev/null
+++ b/usr.sbin/pkg_install/delete/Makefile
@@ -0,0 +1,9 @@
+PROG= pkg_delete
+
+CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib
+LDADD+= -L${.CURDIR}/../lib -L${.CURDIR}/../lib/obj -linstall
+
+
+SRCS= main.c perform.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg_install/delete/delete.h b/usr.sbin/pkg_install/delete/delete.h
new file mode 100644
index 0000000..2828cdf
--- /dev/null
+++ b/usr.sbin/pkg_install/delete/delete.h
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Include and define various things wanted by the delete command.
+ *
+ */
+
+#ifndef _INST_DELETE_H_INCLUDE
+#define _INST_DELETE_H_INCLUDE
+
+extern char *Prefix;
+extern Boolean NoDeInstall;
+extern char *Directory;
+extern char *PkgName;
+
+#endif /* _INST_DELETE_H_INCLUDE */
diff --git a/usr.sbin/pkg_install/delete/main.c b/usr.sbin/pkg_install/delete/main.c
new file mode 100644
index 0000000..a66edfd
--- /dev/null
+++ b/usr.sbin/pkg_install/delete/main.c
@@ -0,0 +1,108 @@
+#ifndef lint
+static char *rcsid = "$Id: main.c,v 1.5 1993/09/04 05:06:38 jkh Exp $";
+#endif
+
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the delete module.
+ *
+ */
+
+#include "lib.h"
+#include "delete.h"
+
+static char Options[] = "hvDnp:";
+
+char *Prefix = NULL;
+Boolean NoDeInstall = FALSE;
+
+int
+main(int argc, char **argv)
+{
+ int ch, err;
+ char **pkgs, **start;
+ char *prog_name = argv[0];
+
+ pkgs = start = argv;
+ while ((ch = getopt(argc, argv, Options)) != EOF)
+ switch(ch) {
+ case 'v':
+ Verbose = TRUE;
+ break;
+
+ case 'p':
+ Prefix = optarg;
+ break;
+
+ case 'D':
+ NoDeInstall = TRUE;
+ break;
+
+ case 'n':
+ Fake = TRUE;
+ Verbose = TRUE;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage(prog_name, NULL);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* Get all the remaining package names, if any */
+ /* Get all the remaining package names, if any */
+ while (*argv)
+ *pkgs++ = *argv++;
+
+ /* If no packages, yelp */
+ if (pkgs == start)
+ usage(prog_name, "Missing package name(s)");
+ *pkgs = NULL;
+ if ((err = pkg_perform(start)) != NULL) {
+ if (Verbose)
+ fprintf(stderr, "%d package deletion(s) failed.\n", err);
+ return err;
+ }
+ else
+ return 0;
+}
+
+void
+usage(const char *name, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (fmt) {
+ fprintf(stderr, "%s: ", name);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n\n");
+ }
+ va_end(args);
+ fprintf(stderr, "Usage: %s [args] pkg [ .. pkg ]\n", name);
+ fprintf(stderr, "Where args are one or more of:\n\n");
+ fprintf(stderr, "-v verbose\n");
+ fprintf(stderr, "-p arg override prefix with arg\n");
+ fprintf(stderr, "-D don't execute pkg de-install script, if any\n");
+ fprintf(stderr, "-n don't actually de-install, just show steps\n");
+ exit(1);
+}
diff --git a/usr.sbin/pkg_install/delete/perform.c b/usr.sbin/pkg_install/delete/perform.c
new file mode 100644
index 0000000..0b94b2c
--- /dev/null
+++ b/usr.sbin/pkg_install/delete/perform.c
@@ -0,0 +1,122 @@
+#ifndef lint
+static const char *rcsid = "$Id: perform.c,v 1.4 1994/05/25 18:00:02 asami Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the main body of the delete module.
+ *
+ */
+
+#include "lib.h"
+#include "delete.h"
+
+static int pkg_do(char *);
+static void sanity_check(char *);
+static char LogDir[FILENAME_MAX];
+
+
+int
+pkg_perform(char **pkgs)
+{
+ int i, err_cnt = 0;
+
+ for (i = 0; pkgs[i]; i++)
+ err_cnt += pkg_do(pkgs[i]);
+ return err_cnt;
+}
+
+static Package Plist;
+
+/* This is seriously ugly code following. Written very fast! */
+static int
+pkg_do(char *pkg)
+{
+ FILE *cfile;
+ char home[FILENAME_MAX];
+ PackingList p;
+
+ /* Reset some state */
+ if (Plist.head)
+ free_plist(&Plist);
+
+ sprintf(LogDir, "%s/%s", LOG_DIR, pkg);
+ if (!fexists(LogDir)) {
+ whinge("No such package '%s' installed.", pkg);
+ return 1;
+ }
+ if (!getcwd(home, FILENAME_MAX))
+ barf("Unable to get current working directory!");
+ if (chdir(LogDir) == FAIL) {
+ whinge("Unable to change directory to %s! Deinstall failed.", LogDir);
+ return 1;
+ }
+ sanity_check(LogDir);
+ cfile = fopen(CONTENTS_FNAME, "r");
+ if (!cfile) {
+ whinge("Unable to open '%s' file.", CONTENTS_FNAME);
+ return 1;
+ }
+ /* If we have a prefix, add it now */
+ if (Prefix)
+ add_plist(&Plist, PLIST_CWD, Prefix);
+ read_plist(&Plist, cfile);
+ fclose(cfile);
+ setenv(PKG_PREFIX_VNAME,
+ (p = find_plist(&Plist, PLIST_CWD)) ? p->name : NULL, 1);
+ if (fexists(REQUIRE_FNAME)) {
+ if (Verbose)
+ printf("Executing 'require' script.\n");
+ vsystem("chmod +x %s", REQUIRE_FNAME); /* be sure */
+ if (vsystem("./%s %s DEINSTALL", REQUIRE_FNAME, pkg)) {
+ whinge("Package %s fails requirements - not deleted.", pkg);
+ return 1;
+ }
+ }
+ if (!NoDeInstall && fexists(DEINSTALL_FNAME)) {
+ if (Fake)
+ printf("Would execute de-install script at this point.\n");
+ else {
+ vsystem("chmod +x %s", DEINSTALL_FNAME); /* make sure */
+ if (vsystem("./%s %s DEINSTALL", DEINSTALL_FNAME, pkg)) {
+ whinge("De-Install script returned error status.");
+ return 1;
+ }
+ }
+ }
+ if (chdir(home) == FAIL)
+ barf("Toto! This doesn't look like Kansas anymore!");
+ if (!Fake && delete_package(FALSE, &Plist) != FAIL &&
+ vsystem("%s -r %s", REMOVE_CMD, LogDir)) {
+ whinge("Couldn't remove log entry in %s, de-install failed.", LogDir);
+ return 1;
+ }
+ return 0;
+}
+
+static void
+sanity_check(char *pkg)
+{
+ if (!fexists(CONTENTS_FNAME))
+ barf("Installed package %s has no %s file!", pkg, CONTENTS_FNAME);
+}
+
+void
+cleanup(int sig)
+{
+ /* Nothing to do */
+}
diff --git a/usr.sbin/pkg_install/delete/pkg_delete.1 b/usr.sbin/pkg_install/delete/pkg_delete.1
new file mode 100644
index 0000000..cde1ba6
--- /dev/null
+++ b/usr.sbin/pkg_install/delete/pkg_delete.1
@@ -0,0 +1,124 @@
+.\"
+.\" FreeBSD install - a package for the installation and maintainance
+.\" of non-core utilities.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" Jordan K. Hubbard
+.\"
+.\"
+.\" @(#)pkg_delete.1
+.\"
+.TH pkg_delete 1 "July 18, 1993" "" "FreeBSD"
+
+.SH NAME
+pkg_delete - a utility for deleting previously installed software package distributions.
+.SH SYNOPSIS
+.na
+.B pkg_delete
+.RB [options]
+.RB "pkg-name\ [.. pkg-name]"
+
+.SH DESCRIPTION
+The
+.B pkg_delete
+command is used to delete packages that have been previously installed
+with the
+.B pkg_add
+command.
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-v
+Turns on verbose output.
+.B "Optional."
+.TP
+.B \-D
+If an de-installation script exists for a given package, do not execute it.
+.B "Optional."
+.TP
+.B \-n
+Don't actually de-install a package, just report the steps that
+would be taken if it was.
+.B "Optional."
+.TP
+.BI "\-p\ " prefix
+Sets
+.I prefix
+as the directory in which to delete files from any installed packages
+which do not explicitly set theirs.
+.B "Optional."
+.PP
+.SH "TECHNICAL DETAILS"
+.B
+pkg_delete
+does pretty much what it says. It looks for a package in /var/db/pkg
+and sets about deleting the files that make up the package and, finally,
+the record of the package itself.
+.PP
+If the package contains a
+.B require
+file (see
+.B pkg_create
+), then this is executed first with the flags
+.PP
+.B <script>
+.I pkg-name DEINSTALL
+.PP
+to see whether or not de-installation should continue (a non-zero exit
+status means no).
+.PP
+If a
+.B de-install
+script exists for the package, it is executed before any files are removed.
+It is this script's responsibility to clean up any additional messy details
+around the package's installation, since all
+.B pkg_delete
+knows how to do is delete the files created in the original distribution.
+The
+.B de-install
+script is called with the flags
+.PP
+.B <script>
+.I pkg-name DEINSTALL
+.PP
+Where
+.I pkg-name
+is the name of the package in question and
+.I DEINSTALL
+is a keyword denoting that this is a deinstallation. Passing the keyword
+lets you potentially write only one program/script that handles all
+aspects of installation and deletion.
+.PP
+All scripts are called with the environment variable
+.B PKG_PREFIX
+set to the installation prefix (see the
+.B -p
+option above). This allows a package author to write a script
+that reliably performs some action on the directory where the package
+is installed, even if the user might have changed it by
+.B -p
+when
+.B pkg_add
+or
+.B pkg_delete
+is run.
+.PP
+.SH BUGS
+Sure to be some.
+.SH "SEE ALSO"
+.BR pkg_create "(" 1 "),"
+.BR pkg_info "(" 1 "),"
+.BR pkg_add "(" 1 "),"
+.SH AUTHORS
+Jordan Hubbard
+
diff --git a/usr.sbin/pkg_install/info/Makefile b/usr.sbin/pkg_install/info/Makefile
new file mode 100644
index 0000000..b7344f3
--- /dev/null
+++ b/usr.sbin/pkg_install/info/Makefile
@@ -0,0 +1,9 @@
+PROG= pkg_info
+
+CFLAGS+= ${DEBUG} -I${.CURDIR}/../lib
+LDADD+= -L${.CURDIR}/../lib -L${.CURDIR}/../lib/obj -linstall
+
+
+SRCS= main.c perform.c show.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg_install/info/info.h b/usr.sbin/pkg_install/info/info.h
new file mode 100644
index 0000000..b978bd4
--- /dev/null
+++ b/usr.sbin/pkg_install/info/info.h
@@ -0,0 +1,47 @@
+/* $Id: info.h,v 1.4 1993/09/04 05:06:40 jkh Exp $ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 23 August 1993
+ *
+ * Include and define various things wanted by the info command.
+ *
+ */
+
+#ifndef _INST_INFO_H_INCLUDE
+#define _INST_INFO_H_INCLUDE
+
+#define SHOW_COMMENT 0x1
+#define SHOW_DESC 0x2
+#define SHOW_PLIST 0x4
+#define SHOW_INSTALL 0x8
+#define SHOW_DEINSTALL 0x10
+#define SHOW_REQUIRE 0x20
+#define SHOW_PREFIX 0x40
+#define SHOW_INDEX 0x80
+#define SHOW_FILES 0x100
+
+extern int Flags;
+extern Boolean AllInstalled;
+extern Boolean Quiet;
+extern char *InfoPrefix;
+extern char *PlayPen;
+extern char *CheckPkg;
+
+extern void show_file(char *, char *);
+extern void show_plist(char *, Package *, plist_t);
+extern void show_files(char *, Package *);
+
+#endif /* _INST_INFO_H_INCLUDE */
diff --git a/usr.sbin/pkg_install/info/main.c b/usr.sbin/pkg_install/info/main.c
new file mode 100644
index 0000000..6132fab
--- /dev/null
+++ b/usr.sbin/pkg_install/info/main.c
@@ -0,0 +1,165 @@
+#ifndef lint
+static char *rcsid = "$Id: main.c,v 1.6 1994/05/25 06:28:14 jkh Exp $";
+#endif
+
+/*
+ *
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * This is the add module.
+ *
+ */
+
+#include "lib.h"
+#include "info.h"
+
+static char Options[] = "acde:fikrpLqIvhl:";
+
+int Flags = 0;
+Boolean AllInstalled = FALSE;
+Boolean Quiet = FALSE;
+char *InfoPrefix = "";
+char *PlayPen = NULL;
+char *CheckPkg = NULL;
+
+int
+main(int argc, char **argv)
+{
+ int ch;
+ char **pkgs, **start;
+ char *prog_name = argv[0];
+
+ pkgs = start = argv;
+ while ((ch = getopt(argc, argv, Options)) != EOF)
+ switch(ch) {
+ case 'a':
+ AllInstalled = TRUE;
+ break;
+
+ case 'v':
+ Verbose = TRUE;
+ /* Reasonable definition of 'everything' */
+ Flags = SHOW_COMMENT | SHOW_DESC | SHOW_PLIST | SHOW_INSTALL |
+ SHOW_DEINSTALL | SHOW_REQUIRE;
+ break;
+
+ case 'I':
+ Flags |= SHOW_INDEX;
+ break;
+
+ case 'p':
+ Flags |= SHOW_PREFIX;
+ break;
+
+ case 'c':
+ Flags |= SHOW_COMMENT;
+ break;
+
+ case 'd':
+ Flags |= SHOW_DESC;
+ break;
+
+ case 'f':
+ Flags |= SHOW_PLIST;
+ break;
+
+ case 'i':
+ Flags |= SHOW_INSTALL;
+ break;
+
+ case 'k':
+ Flags |= SHOW_DEINSTALL;
+ break;
+
+ case 'r':
+ Flags |= SHOW_REQUIRE;
+ break;
+
+ case 'L':
+ Flags |= SHOW_FILES;
+ break;
+
+ case 'l':
+ InfoPrefix = optarg;
+ break;
+
+ case 'q':
+ Quiet = TRUE;
+ break;
+
+ case 't':
+ PlayPen = optarg;
+ break;
+
+ case 'e':
+ CheckPkg = optarg;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage(prog_name, NULL);
+ break;
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ /* Set some reasonable defaults */
+ if (!Flags)
+ Flags = SHOW_COMMENT | SHOW_DESC;
+
+ /* Get all the remaining package names, if any */
+ while (*argv)
+ *pkgs++ = *argv++;
+
+ /* If no packages, yelp */
+ if (pkgs == start && !AllInstalled && !CheckPkg)
+ usage(prog_name, "Missing package name(s)");
+ *pkgs = NULL;
+ return pkg_perform(start);
+}
+
+void
+usage(const char *name, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (fmt) {
+ fprintf(stderr, "%s: ", name);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n\n");
+ }
+ va_end(args);
+ fprintf(stderr, "Usage: %s [args] pkg [ .. pkg ]\n", name);
+ fprintf(stderr, "Where args are one or more of:\n\n");
+ fprintf(stderr, "-a show all installed packages (if any)\n");
+ fprintf(stderr, "-I print 'index' of packages\n");
+ fprintf(stderr, "-c print `one line comment'\n");
+ fprintf(stderr, "-d print description\n");
+ fprintf(stderr, "-f show packing list\n");
+ fprintf(stderr, "-i show install script\n");
+ fprintf(stderr, "-k show deinstall script\n");
+ fprintf(stderr, "-r show requirements script\n");
+ fprintf(stderr, "-p show prefix\n");
+ fprintf(stderr, "-l <str> Prefix each info catagory with <str>\n");
+ fprintf(stderr, "-v show all information\n");
+ fprintf(stderr, "-t temp use temp as template for mktemp()\n");
+ fprintf(stderr, "-e pkg returns 0 if pkg is installed, 1 otherwise\n");
+ fprintf(stderr, "\n[no args = -c -d]\n");
+ exit(1);
+}
diff --git a/usr.sbin/pkg_install/info/perform.c b/usr.sbin/pkg_install/info/perform.c
new file mode 100644
index 0000000..53a2135
--- /dev/null
+++ b/usr.sbin/pkg_install/info/perform.c
@@ -0,0 +1,156 @@
+#ifndef lint
+static const char *rcsid = "$Id: perform.c,v 1.4 1993/09/04 05:06:43 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 23 Aug 1993
+ *
+ * This is the main body of the info module.
+ *
+ */
+
+#include "lib.h"
+#include "info.h"
+
+#include <signal.h>
+
+static int pkg_do(char *);
+
+int
+pkg_perform(char **pkgs)
+{
+ int i, err_cnt = 0;
+
+ signal(SIGINT, cleanup);
+
+ /* Overriding action? */
+ if (AllInstalled || CheckPkg) {
+ if (isdir(LOG_DIR)) {
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = opendir(LOG_DIR);
+ if (dirp) {
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
+ if (CheckPkg) {
+ if (!strcmp(dp->d_name, CheckPkg))
+ return 0;
+ }
+ else
+ err_cnt += pkg_do(dp->d_name);
+ }
+ }
+ (void)closedir(dirp);
+ if (CheckPkg)
+ return 1;
+ }
+ else
+ ++err_cnt;
+ }
+ }
+ for (i = 0; pkgs[i]; i++)
+ err_cnt += pkg_do(pkgs[i]);
+ return err_cnt;
+}
+
+static int
+pkg_do(char *pkg)
+{
+ Boolean installed = FALSE;
+ char log_dir[FILENAME_MAX];
+ char *home;
+ Package plist;
+ FILE *fp;
+
+ if (fexists(pkg)) {
+ char fname[FILENAME_MAX];
+
+ home = make_playpen(PlayPen);
+ if (pkg[0] == '/')
+ strcpy(fname, pkg);
+ else
+ sprintf(fname, "%s/%s", home, pkg);
+ if (unpack(fname, "+*")) {
+ whinge("Error during unpacking, no info for '%s' available.", pkg);
+ return 1;
+ }
+ }
+ else {
+ sprintf(log_dir, "%s/%s", LOG_DIR, pkg);
+ if (!fexists(log_dir)) {
+ whinge("Can't find package '%s' installed or in a file!", pkg);
+ return 1;
+ }
+ if (chdir(log_dir) == FAIL) {
+ whinge("Can't change directory to '%s'!", log_dir);
+ return 1;
+ }
+ installed = TRUE;
+ }
+
+ /* Suck in the contents list */
+ plist.head = plist.tail = NULL;
+ fp = fopen(CONTENTS_FNAME, "r");
+ if (!fp) {
+ whinge("Unable to open %s file.", CONTENTS_FNAME);
+ return 1;
+ }
+ /* If we have a prefix, add it now */
+ read_plist(&plist, fp);
+ fclose(fp);
+
+ /*
+ * Index is special info type that has to override all others to make
+ * any sense.
+ */
+ if (Flags & SHOW_INDEX) {
+ char fname[FILENAME_MAX];
+
+ sprintf(fname, "%s\t", pkg);
+ show_file(fname, COMMENT_FNAME);
+ }
+ else {
+ /* Start showing the package contents */
+ if (!Quiet)
+ printf("%sInformation for %s:\n\n", InfoPrefix, pkg);
+ if (Flags & SHOW_COMMENT)
+ show_file("Comment:\n", COMMENT_FNAME);
+ if (Flags & SHOW_DESC)
+ show_file("Description:\n", DESC_FNAME);
+ if (Flags & SHOW_PLIST)
+ show_plist("Packing list:\n", &plist, (plist_t)-1);
+ if ((Flags & SHOW_INSTALL) && fexists(INSTALL_FNAME))
+ show_file("Install script:\n", INSTALL_FNAME);
+ if ((Flags & SHOW_DEINSTALL) && fexists(DEINSTALL_FNAME))
+ show_file("De-Install script:\n", DEINSTALL_FNAME);
+ if (Flags & SHOW_PREFIX)
+ show_plist("Prefix(s):\n", &plist, PLIST_CWD);
+ if (Flags & SHOW_FILES)
+ show_files("Files:\n", &plist);
+ if (!Quiet)
+ puts(InfoPrefix);
+ }
+ free_plist(&plist);
+ leave_playpen();
+ return 0;
+}
+
+void
+cleanup(int sig)
+{
+ leave_playpen();
+}
diff --git a/usr.sbin/pkg_install/info/pkg_info.1 b/usr.sbin/pkg_install/info/pkg_info.1
new file mode 100644
index 0000000..1f28c17
--- /dev/null
+++ b/usr.sbin/pkg_install/info/pkg_info.1
@@ -0,0 +1,123 @@
+.\"
+.\" FreeBSD install - a package for the installation and maintainance
+.\" of non-core utilities.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" Jordan K. Hubbard
+.\"
+.\"
+.\" @(#)pkg_info.1
+.\"
+.TH pkg_info 1 "July 18, 1993" "" "FreeBSD"
+
+.SH NAME
+pkg_info - a utility for getting information on software package distributions.
+.SH SYNOPSIS
+.na
+.B pkg_info
+.RB [options]
+.RB "pkg-file|pkg-name\ [.. pkg-file|pkg-name]"
+
+.SH DESCRIPTION
+The
+.B pkg_info
+command is used to dump out information for packages, either packed up in
+files or already installed on the system
+with the
+.B pkg_create
+command.
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.B \-a
+Show all currently installed packages.
+.TP
+.B \-v
+Turns on verbose output.
+.TP
+.B \-p
+Show the installation prefix for each package.
+.TP
+.B \-q
+Be "quiet" in emitting report headers and such, just dump the
+raw info (basically, assume a non-human reading).
+.TP
+.B \-c
+Show the comment (one liner) field for each package.
+.TP
+.B \-d
+Show the long description field for each package.
+.TP
+.B \-f
+Show the packing list instructions for each package.
+.TP
+.B \-i
+Show the install script (if any) for each package.
+.TP
+.B \-k
+Show the de-install script (if any) for each package.
+.TP
+.B \-r
+Show the requirements script (if any) for each package.
+.TP
+.B \-L
+Show the files within each package. This is different from just
+viewing the packing list, since full pathnames for everything
+are generated.
+.TP
+.BI "\-e\ " pkg-name
+If the package identified by
+.I pkg-name
+is currently installed, return 0, otherwise return 1. This option
+allows you to easily test for the presence of another (perhaps
+prerequisite) package from a script.
+.TP
+.BI "\-l\ " str
+Prefix each information catagory header (see
+.I \-q)
+shown with
+.I str.
+This is primarily of use to front-end programs who want to request a
+lot of different information fields at once for a package, but don't
+necessary want the output intermingled in such a way that they can't
+organize it. This lets you add a special token to the start of
+each field.
+.TP
+.BI "\-t\ " template
+Use
+.I template
+as the input to mktemp(3). By default, this is the string
+.B /tmp/instmp.XXXXXX
+, but it may be necessary to override it in the situation where
+space in your
+.B /tmp
+directory is limited. Be sure to leave some number of `X' characters
+for mktemp(3) to fill in with a unique ID.
+Note: This should really not be necessary with pkg_info,
+since very little information is extracted from each package
+and one would have to have a very small /tmp indeed to overflow
+it.
+.PP
+.SH "TECHNICAL DETAILS"
+Package info is either extracted from files supplied on the
+command line, or from already installed package information
+in /var/db/pkg/<pkg-name>.
+.SH BUGS
+Sure to be some.
+.SH "SEE ALSO"
+.BR pkg_add "(" 1 "),"
+.BR pkg_create "(" 1 "),"
+.BR pkg_delete "(" 1 "),"
+.SH AUTHORS
+Jordan Hubbard
+
diff --git a/usr.sbin/pkg_install/info/show.c b/usr.sbin/pkg_install/info/show.c
new file mode 100644
index 0000000..3000ccf
--- /dev/null
+++ b/usr.sbin/pkg_install/info/show.c
@@ -0,0 +1,145 @@
+#ifndef lint
+static const char *rcsid = "$Id: show.c,v 1.4 1993/09/04 05:06:44 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 23 Aug 1993
+ *
+ * Various display routines for the info module.
+ *
+ */
+
+#include "lib.h"
+#include "info.h"
+
+void
+show_file(char *title, char *fname)
+{
+ FILE *fp;
+ char line[1024];
+ int n;
+
+ if (!Quiet)
+ printf("%s%s", InfoPrefix, title);
+ fp = fopen(fname, "r");
+ if (!fp) {
+ whinge("show_file: Can't open '%s' for reading.", fname);
+ return;
+ }
+ while (n = fread(line, 1, 1024, fp))
+ fwrite(line, 1, n, stdout);
+ fclose(fp);
+ printf("\n"); /* just in case */
+}
+
+/* Show a packing list item type. If type is -1, show all */
+void
+show_plist(char *title, Package *plist, plist_t type)
+{
+ PackingList p;
+ Boolean ign = FALSE;
+
+ if (!Quiet)
+ printf("%s%s", InfoPrefix, title);
+ p = plist->head;
+ while (p) {
+ if (p->type != type && type != -1) {
+ p = p->next;
+ continue;
+ }
+ switch(p->type) {
+ case PLIST_FILE:
+ if (ign) {
+ printf(Quiet ? "%s\n" : "File: %s (ignored)\n", p->name);
+ ign = FALSE;
+ }
+ else
+ printf(Quiet ? "%s\n" : "File: %s\n", p->name);
+ break;
+
+ case PLIST_CWD:
+ printf(Quiet ? "@cwd %s\n" : "\tCWD to %s\n", p->name);
+ break;
+
+ case PLIST_CMD:
+ printf(Quiet ? "@exec %s\n" : "\tEXEC '%s'\n", p->name);
+ break;
+
+ case PLIST_CHMOD:
+ printf(Quiet ? "@chmod %s\n" : "\tCHMOD to %s\n",
+ p->name ? p->name : "(clear default)");
+ break;
+
+ case PLIST_CHOWN:
+ printf(Quiet ? "@chown %s\n" : "\tCHOWN to %s\n",
+ p->name ? p->name : "(clear default)");
+ break;
+
+ case PLIST_CHGRP:
+ printf(Quiet ? "@chgrp %s\n" : "\tCHGRP to %s\n",
+ p->name ? p->name : "(clear default)");
+ break;
+
+ case PLIST_COMMENT:
+ printf(Quiet ? "@comment %s\n" : "\tComment: %s\n", p->name);
+ break;
+
+ case PLIST_IGNORE:
+ ign = TRUE;
+ break;
+
+ case PLIST_NAME:
+ printf(Quiet ? "@name %s\n" : "\tPackage name: %s\n", p->name);
+ break;
+
+ default:
+ barf("Unknown command type %d (%s)\n", p->type, p->name);
+ break;
+ }
+ p = p->next;
+ }
+}
+
+/* Show all files in the packing list (except ignored ones) */
+void
+show_files(char *title, Package *plist)
+{
+ PackingList p;
+ Boolean ign = FALSE;
+ char *dir = ".";
+
+ if (!Quiet)
+ printf("%s%s", InfoPrefix, title);
+ p = plist->head;
+ while (p) {
+ switch(p->type) {
+ case PLIST_FILE:
+ if (!ign)
+ printf("%s/%s\n", dir, p->name);
+ ign = FALSE;
+ break;
+
+ case PLIST_CWD:
+ dir = p->name;
+ break;
+
+ case PLIST_IGNORE:
+ ign = TRUE;
+ break;
+ }
+ p = p->next;
+ }
+}
diff --git a/usr.sbin/pkg_install/lib/Makefile b/usr.sbin/pkg_install/lib/Makefile
new file mode 100644
index 0000000..1f802f6
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/Makefile
@@ -0,0 +1,9 @@
+LIB= install
+SRCS= file.c msg.c plist.c str.c exec.c global.c pen.c
+CFLAGS+= ${DEBUG}
+NOPROFILE= yes
+
+install:
+ @echo -n
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/pkg_install/lib/exec.c b/usr.sbin/pkg_install/lib/exec.c
new file mode 100644
index 0000000..5232dd2
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/exec.c
@@ -0,0 +1,48 @@
+#ifndef lint
+static const char *rcsid = "$Id: exec.c,v 1.4 1993/09/04 05:06:47 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Miscellaneous system routines.
+ *
+ */
+
+#include "lib.h"
+
+/*
+ * Unusual system() substitute. Accepts format string and args,
+ * builds and executes command. Returns exit code.
+ */
+
+int
+vsystem(const char *fmt, ...)
+{
+ va_list args;
+ char cmd[FILENAME_MAX * 2]; /* reasonable default for what I do */
+ int ret;
+
+ va_start(args, fmt);
+ vsprintf(cmd, fmt, args);
+#ifdef DEBUG
+printf("Executing %s\n", cmd);
+#endif
+ ret = system(cmd);
+ va_end(args);
+ return ret;
+}
+
diff --git a/usr.sbin/pkg_install/lib/file.c b/usr.sbin/pkg_install/lib/file.c
new file mode 100644
index 0000000..698fd87
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/file.c
@@ -0,0 +1,232 @@
+#ifndef lint
+static const char *rcsid = "$Id: file.c,v 1.4 1993/09/06 23:28:42 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Miscellaneous file access utilities.
+ *
+ */
+
+#include "lib.h"
+
+/* Quick check to see if a file exists */
+Boolean
+fexists(char *fname)
+{
+ if (!access(fname, F_OK))
+ return TRUE;
+ return FALSE;
+}
+
+/* Quick check to see if something is a directory */
+Boolean
+isdir(char *fname)
+{
+ struct stat sb;
+
+ if (stat(fname, &sb) != FAIL &&
+ (sb.st_mode & S_IFDIR))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Check to see if file is a dir, and is empty */
+Boolean
+isempty(char *fname)
+{
+ if (isdir(fname)) {
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = opendir(fname);
+ if (!dirp)
+ return FALSE; /* no perms, leave it alone */
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
+ if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) {
+ closedir(dirp);
+ return FALSE;
+ }
+ }
+ (void)closedir(dirp);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+char *
+get_file_contents(char *fname)
+{
+ char *contents;
+ struct stat sb;
+ int fd;
+
+ if (stat(fname, &sb) == FAIL)
+ barf("Can't stat '%s'.", fname);
+
+ contents = (char *)malloc(sb.st_size + 1);
+ fd = open(fname, O_RDONLY, 0);
+ if (fd == FAIL)
+ barf("Unable to open '%s' for reading.", fname);
+ if (read(fd, contents, sb.st_size) != sb.st_size)
+ barf("Short read on '%s' - did not get %d bytes.", fname, sb.st_size);
+ close(fd);
+ contents[sb.st_size] = '\0';
+ return contents;
+}
+
+/* Write the contents of "str" to a file */
+void
+write_file(char *name, char *str)
+{
+ FILE *fp;
+ int len;
+
+ fp = fopen(name, "w");
+ if (!fp)
+ barf("Can't fopen '%s' for writing.", name);
+ len = strlen(str);
+ if (fwrite(str, 1, len, fp) != len)
+ barf("Short fwrite on '%s', tried to write %d bytes.", name, len);
+ if (fclose(fp))
+ barf("failure to fclose '%s'.", name);
+}
+
+void
+copy_file(char *dir, char *fname, char *to)
+{
+ char cmd[FILENAME_MAX];
+
+ if (fname[0] == '/')
+ sprintf(cmd, "cp -p -r %s %s", fname, to);
+ else
+ sprintf(cmd, "cp -p -r %s/%s %s", dir, fname, to);
+ if (vsystem(cmd))
+ barf("Couldn't perform '%s'", cmd);
+}
+
+/*
+ * Copy a hierarchy (possibly from dir) to the current directory, or
+ * if "to" is TRUE, from the current directory to a location someplace
+ * else.
+ *
+ * Though slower, using tar to copy preserves symlinks and everything
+ * without me having to write some big hairy routine to do it.
+ */
+void
+copy_hierarchy(char *dir, char *fname, Boolean to)
+{
+ char cmd[FILENAME_MAX * 3];
+
+ if (!to) {
+ /* If absolute path, use it */
+ if (*fname == '/')
+ dir = "/";
+ sprintf(cmd, "tar cf - -C %s %s | tar xpf -", dir, fname);
+ }
+ else
+ sprintf(cmd, "tar cf - %s | tar xpf - -C %s", fname, dir);
+#ifdef DEBUG
+ printf("Using '%s' to copy trees.\n", cmd);
+#endif
+ if (system(cmd))
+ barf("copy_file: Couldn't perform '%s'", cmd);
+}
+
+/* Unpack a tar file */
+int
+unpack(char *pkg, char *flist)
+{
+ char args[10], suffix[80], *cp;
+
+ /*
+ * Figure out by a crude heuristic whether this or not this is probably
+ * compressed.
+ */
+ cp = rindex(pkg, '.');
+ if (cp) {
+ strcpy(suffix, cp + 1);
+ if (index(suffix, 'z') || index(suffix, 'Z'))
+ strcpy(args, "z");
+ }
+ strcat(args, "xpf");
+ if (vsystem("tar %s %s %s", args, pkg, flist ? flist : "")) {
+ whinge("Tar extract of %s failed!", pkg);
+ return 1;
+ }
+ return 0;
+}
+
+/* Using fmt, replace all instances of:
+ *
+ * %F With the parameter "name"
+ * %D With the parameter "dir"
+ * %B Return the directory part ("base") of %D/%F
+ * %f Return the filename part of %D/%F
+ *
+ * Does not check for overflow - caution!
+ *
+ */
+void
+format_cmd(char *buf, char *fmt, char *dir, char *name)
+{
+ char *cp, scratch[FILENAME_MAX * 2];
+
+ while (*fmt) {
+ if (*fmt == '%') {
+ switch (*++fmt) {
+ case 'F':
+ strcpy(buf, name);
+ buf += strlen(name);
+ break;
+
+ case 'D':
+ strcpy(buf, dir);
+ buf += strlen(dir);
+ break;
+
+ case 'B':
+ sprintf(scratch, "%s/%s", dir, name);
+ cp = &scratch[strlen(scratch) - 1];
+ while (cp != scratch && *cp != '/')
+ --cp;
+ *cp = '\0';
+ strcpy(buf, scratch);
+ buf += strlen(scratch);
+ break;
+
+ case 'f':
+ sprintf(scratch, "%s/%s", dir, name);
+ cp = &scratch[strlen(scratch) - 1];
+ while (cp != scratch && *(cp - 1) != '/')
+ --cp;
+ strcpy(buf, cp);
+ buf += strlen(cp);
+ break;
+
+ default:
+ *buf++ = *fmt;
+ break;
+ }
+ ++fmt;
+ }
+ else
+ *buf++ = *fmt++;
+ }
+ *buf = '\0';
+}
diff --git a/usr.sbin/pkg_install/lib/global.c b/usr.sbin/pkg_install/lib/global.c
new file mode 100644
index 0000000..d411f5e
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/global.c
@@ -0,0 +1,33 @@
+#ifndef lint
+static const char *rcsid = "$Id: global.c,v 1.1.1.1 1993/08/26 01:19:55 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+
+ * 18 July 1993
+ *
+ * Semi-convenient place to stick some needed globals.
+ *
+ */
+
+#include "lib.h"
+
+/* These are global for all utils */
+Boolean Verbose = FALSE;
+Boolean Fake = FALSE;
+int AutoAnswer = FALSE;
+
+
diff --git a/usr.sbin/pkg_install/lib/lib.h b/usr.sbin/pkg_install/lib/lib.h
new file mode 100644
index 0000000..08de0be
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/lib.h
@@ -0,0 +1,155 @@
+/* $Id: lib.h,v 1.8 1994/08/28 14:15:29 jkh Exp $ */
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Include and define various things wanted by the library routines.
+ *
+ */
+
+#ifndef _INST_LIB_LIB_H_
+#define _INST_LIB_LIB_H_
+
+/* Includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/file.h>
+
+/* Macros */
+#define SUCCESS (0)
+#define FAIL (-1)
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+#define YES 2
+#define NO 1
+
+/* Usually "rm", but often "echo" during debugging! */
+#define REMOVE_CMD "rm"
+
+/* Usually "rm", but often "echo" during debugging! */
+#define RMDIR_CMD "rmdir"
+
+/* Where we put logging information */
+#define LOG_DIR "/var/db/pkg"
+
+/* The names of our "special" files */
+#define CONTENTS_FNAME "+CONTENTS"
+#define COMMENT_FNAME "+COMMENT"
+#define DESC_FNAME "+DESC"
+#define INSTALL_FNAME "+INSTALL"
+#define DEINSTALL_FNAME "+DEINSTALL"
+#define REQUIRE_FNAME "+REQUIRE"
+
+#define CMD_CHAR '@' /* prefix for extended PLIST cmd */
+
+/* The name of the "prefix" environment variable given to scripts */
+#define PKG_PREFIX_VNAME "PKG_PREFIX"
+
+enum _plist_t {
+ PLIST_FILE, PLIST_CWD, PLIST_CMD, PLIST_CHMOD,
+ PLIST_CHOWN, PLIST_CHGRP, PLIST_COMMENT,
+ PLIST_IGNORE, PLIST_NAME, PLIST_UNEXEC, PLIST_SRC
+};
+typedef enum _plist_t plist_t;
+
+/* Types */
+typedef unsigned int Boolean;
+
+struct _plist {
+ struct _plist *prev, *next;
+ char *name;
+ Boolean marked;
+ plist_t type;
+};
+typedef struct _plist *PackingList;
+
+struct _pack {
+ struct _plist *head, *tail;
+};
+typedef struct _pack Package;
+
+/* Prototypes */
+/* Misc */
+int vsystem(const char *, ...);
+void cleanup(int);
+char *make_playpen(char *);
+void leave_playpen(void);
+char *where_playpen(void);
+
+/* String */
+char *get_dash_string(char **);
+char *copy_string(char *);
+Boolean suffix(char *, char *);
+void nuke_suffix(char *);
+void str_lowercase(char *);
+
+/* File */
+Boolean fexists(char *);
+Boolean isdir(char *);
+Boolean isempty(char *);
+char *get_file_contents(char *);
+void write_file(char *, char *);
+void copy_file(char *, char *, char *);
+void copy_hierarchy(char *, char *, Boolean);
+int delete_hierarchy(char *, Boolean);
+int unpack(char *, char *);
+void format_cmd(char *, char *, char *, char *);
+
+/* Msg */
+void upchuck(const char *);
+void barf(const char *, ...);
+void whinge(const char *, ...);
+Boolean y_or_n(Boolean, const char *, ...);
+
+/* Packing list */
+PackingList new_plist_entry(void);
+PackingList last_plist(Package *);
+PackingList find_plist(Package *, plist_t);
+void plist_delete(Package *, Boolean, plist_t, char *);
+void free_plist(Package *);
+void mark_plist(Package *);
+void csum_plist_entry(char *, PackingList);
+void add_plist(Package *, plist_t, char *);
+void add_plist_top(Package *, plist_t, char *);
+void write_plist(Package *, FILE *);
+void read_plist(Package *, FILE *);
+int plist_cmd(char *, char **);
+int delete_package(Boolean, Package *);
+
+/* For all */
+void usage(const char *, const char *, ...);
+int pkg_perform(char **);
+
+/* Externs */
+extern Boolean Verbose;
+extern Boolean Fake;
+extern int AutoAnswer;
+
+#endif /* _INST_LIB_LIB_H_ */
diff --git a/usr.sbin/pkg_install/lib/msg.c b/usr.sbin/pkg_install/lib/msg.c
new file mode 100644
index 0000000..9e3e8ef
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/msg.c
@@ -0,0 +1,103 @@
+#ifndef lint
+static const char *rcsid = "$Id: msg.c,v 1.3 1994/04/05 14:08:47 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+
+ * 18 July 1993
+ *
+ * Miscellaneous message routines.
+ *
+ */
+
+#include "lib.h"
+
+/* Die a relatively simple death */
+void
+upchuck(const char *err)
+{
+ fprintf(stderr, "Fatal error during execution: ");
+ perror(err);
+ cleanup(0);
+ exit(1);
+}
+
+/* Die a more complex death */
+void
+barf(const char *err, ...)
+{
+ va_list args;
+
+ va_start(args, err);
+ vfprintf(stderr, err, args);
+ fputc('\n', stderr);
+ va_end(args);
+ cleanup(0);
+ exit(2);
+}
+
+/* Get annoyed about something but don't go to pieces over it */
+void
+whinge(const char *err, ...)
+{
+ va_list args;
+
+ va_start(args, err);
+ vfprintf(stderr, err, args);
+ fputc('\n', stderr);
+ va_end(args);
+}
+
+/*
+ * As a yes/no question, prompting from the varargs string and using
+ * default if user just hits return.
+ */
+Boolean
+y_or_n(Boolean def, const char *msg, ...)
+{
+ va_list args;
+ int ch = 0;
+ FILE *tty;
+
+ va_start(args, msg);
+ /*
+ * Need to open /dev/tty because file collection may have been
+ * collected on stdin
+ */
+ tty = fopen("/dev/tty", "r");
+ if (!tty)
+ barf("Can't open /dev/tty!\n");
+ while (ch != 'Y' && ch != 'N') {
+ vfprintf(stderr, msg, args);
+ if (def)
+ fprintf(stderr, " [yes]? ");
+ else
+ fprintf(stderr, " [no]? ");
+ fflush(stderr);
+ if (AutoAnswer) {
+ ch = (AutoAnswer == YES) ? 'Y' : 'N';
+ fprintf(stderr, "%c\n", ch);
+ }
+ else
+ ch = toupper(fgetc(tty));
+ if (ch == '\n')
+ ch = (def) ? 'Y' : 'N';
+ }
+ fclose(tty) ;
+ return (ch == 'Y') ? TRUE : FALSE;
+}
+
+
diff --git a/usr.sbin/pkg_install/lib/pen.c b/usr.sbin/pkg_install/lib/pen.c
new file mode 100644
index 0000000..1872d82
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/pen.c
@@ -0,0 +1,74 @@
+#ifndef lint
+static const char *rcsid = "$Id: pen.c,v 1.2 1993/09/04 05:06:51 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Routines for managing the "play pen".
+ *
+ */
+
+#include "lib.h"
+
+/* For keeping track of where we are */
+static char Cwd[FILENAME_MAX];
+static char Pen[FILENAME_MAX];
+
+
+/*
+ * Make a temporary directory to play in and chdir() to it, returning
+ * pathname of previous working directory.
+ */
+char *
+make_playpen(char *pen)
+{
+ if (!pen)
+ pen = "/tmp/instmp.XXXXXX";
+ if (!getcwd(Cwd, FILENAME_MAX))
+ upchuck("getcwd");
+ strcpy(Pen, pen);
+ if (!mktemp(Pen))
+ barf("Can't mktemp '%s'.", Pen);
+ if (mkdir(Pen, 0755) == FAIL)
+ barf("Can't mkdir '%s'.", Pen);
+ if (chdir(Pen) == FAIL)
+ barf("Can't chdir to '%s'.", Pen);
+ return Cwd;
+}
+
+/* Convenience routine for getting out of playpen */
+void
+leave_playpen(void)
+{
+ if (Cwd[0]) {
+ if (chdir(Cwd) == FAIL)
+ barf("Can't chdir back to '%s'.", Cwd);
+ if (vsystem("rm -rf %s", Pen))
+ fprintf(stderr, "Couldn't remove temporary dir '%s'\n", Pen);
+ Cwd[0] = '\0';
+ }
+}
+
+/* Accessor function for telling us where the pen is */
+char *
+where_playpen(void)
+{
+ if (Cwd[0])
+ return Pen;
+ else
+ return NULL;
+}
diff --git a/usr.sbin/pkg_install/lib/plist.c b/usr.sbin/pkg_install/lib/plist.c
new file mode 100644
index 0000000..577ae5e
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/plist.c
@@ -0,0 +1,366 @@
+#ifndef lint
+static const char *rcsid = "$Id: plist.c,v 1.8 1994/08/28 14:15:30 jkh Exp $";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * General packing list routines.
+ *
+ */
+
+#include "lib.h"
+
+/* Add an item to a packing list */
+void
+add_plist(Package *p, plist_t type, char *arg)
+{
+ PackingList tmp;
+
+ tmp = new_plist_entry();
+ tmp->name = copy_string(arg);
+ tmp->type = type;
+
+ if (!p->head)
+ p->head = p->tail = tmp;
+ else {
+ tmp->prev = p->tail;
+ p->tail->next = tmp;
+ p->tail = tmp;
+ }
+}
+
+void
+add_plist_top(Package *p, plist_t type, char *arg)
+{
+ PackingList tmp;
+
+ tmp = new_plist_entry();
+ tmp->name = copy_string(arg);
+ tmp->type = type;
+
+ if (!p->head)
+ p->head = p->tail = tmp;
+ else {
+ tmp->next = p->head;
+ p->head->prev = tmp;
+ p->head = tmp;
+ }
+}
+
+/* Return the last (most recent) entry in a packing list */
+PackingList
+last_plist(Package *p)
+{
+ return p->tail;
+}
+
+/* Mark all items in a packing list to prevent iteration over them */
+void
+mark_plist(Package *pkg)
+{
+ PackingList p = pkg->head;
+
+ while (p) {
+ p->marked = TRUE;
+ p = p->next;
+ }
+}
+
+/* Find a given item in a packing list and, if so, return it (else NULL) */
+PackingList
+find_plist(Package *pkg, plist_t type)
+{
+ PackingList p = pkg->head;
+
+ while (p) {
+ if (p->type == type)
+ return p;
+ p = p->next;
+ }
+ return NULL;
+}
+
+/*
+ * Delete plist item 'type' in the list (if 'name' is non-null, match it
+ * too.) If 'all' is set, delete all items, not just the first occurance.
+ */
+void
+delete_plist(Package *pkg, Boolean all, plist_t type, char *name)
+{
+ PackingList p = pkg->head;
+
+ while (p) {
+ PackingList pnext = p->next;
+
+ if (p->type == type && (!name || !strcmp(name, p->name))) {
+ free(p->name);
+ if (p->prev)
+ p->prev->next = pnext;
+ else
+ pkg->head = pnext;
+ if (pnext)
+ pnext->prev = p->prev;
+ else
+ pkg->tail = p->prev;
+ free(p);
+ if (!all)
+ return;
+ p = pnext;
+ }
+ else
+ p = p->next;
+ }
+}
+
+/* Allocate a new packing list entry */
+PackingList
+new_plist_entry(void)
+{
+ PackingList ret;
+
+ ret = (PackingList)malloc(sizeof(struct _plist));
+ bzero(ret, sizeof(struct _plist));
+ return ret;
+}
+
+/* Free an entire packing list */
+void
+free_plist(Package *pkg)
+{
+ PackingList p = pkg->head;
+
+ while (p) {
+ PackingList p1 = p->next;
+
+ free(p->name);
+ free(p);
+ p = p1;
+ }
+ pkg->head = pkg->tail = NULL;
+}
+
+/*
+ * For an ascii string denoting a plist command, return its code and
+ * optionally its argument(s)
+ */
+int
+plist_cmd(char *s, char **arg)
+{
+ char cmd[FILENAME_MAX + 20]; /* 20 == fudge for max cmd len */
+ char *cp, *sp;
+
+ strcpy(cmd, s);
+ str_lowercase(cmd);
+ cp = cmd;
+ sp = s;
+ while (*cp) {
+ if (isspace(*cp)) {
+ *cp = '\0';
+ while (isspace(*sp)) /* Never sure if macro, increment later */
+ ++sp;
+ break;
+ }
+ ++cp, ++sp;
+ }
+ if (arg)
+ *arg = sp;
+ if (!strcmp(cmd, "cwd"))
+ return PLIST_CWD;
+ else if (!strcmp(cmd, "srcdir"))
+ return PLIST_SRC;
+ else if (!strcmp(cmd, "cd"))
+ return PLIST_CWD;
+ else if (!strcmp(cmd, "exec"))
+ return PLIST_CMD;
+ else if (!strcmp(cmd, "unexec"))
+ return PLIST_UNEXEC;
+ else if (!strcmp(cmd, "mode"))
+ return PLIST_CHMOD;
+ else if (!strcmp(cmd, "owner"))
+ return PLIST_CHOWN;
+ else if (!strcmp(cmd, "group"))
+ return PLIST_CHGRP;
+ else if (!strcmp(cmd, "comment"))
+ return PLIST_COMMENT;
+ else if (!strcmp(cmd, "ignore"))
+ return PLIST_IGNORE;
+ else if (!strcmp(cmd, "name"))
+ return PLIST_NAME;
+ else
+ return FAIL;
+}
+
+/* Read a packing list from a file */
+void
+read_plist(Package *pkg, FILE *fp)
+{
+ char *cp, pline[FILENAME_MAX];
+ int cmd;
+
+ while (fgets(pline, FILENAME_MAX, fp)) {
+ int len = strlen(pline) - 1;
+
+ while (isspace(pline[len]))
+ pline[len--] = '\0';
+ if (len <= 0)
+ continue;
+ cp = pline;
+ if (pline[0] == CMD_CHAR) {
+ cmd = plist_cmd(pline + 1, &cp);
+ if (cmd == FAIL)
+ barf("Bad command '%s'", pline);
+ if (*cp == '\0')
+ cp = NULL;
+ }
+ else
+ cmd = PLIST_FILE;
+ add_plist(pkg, cmd, cp);
+ }
+}
+
+/* Write a packing list to a file, converting commands to ascii equivs */
+void
+write_plist(Package *pkg, FILE *fp)
+{
+ PackingList plist = pkg->head;
+
+ while (plist) {
+ switch(plist->type) {
+ case PLIST_FILE:
+ fprintf(fp, "%s\n", plist->name);
+ break;
+
+ case PLIST_CWD:
+ fprintf(fp, "%ccwd %s\n", CMD_CHAR, plist->name);
+ break;
+
+ case PLIST_SRC:
+ fprintf(fp, "%csrcdir %s\n", CMD_CHAR, plist->name);
+ break;
+
+ case PLIST_CMD:
+ fprintf(fp, "%cexec %s\n", CMD_CHAR, plist->name);
+ break;
+
+ case PLIST_UNEXEC:
+ fprintf(fp, "%cunexec %s\n", CMD_CHAR, plist->name);
+ break;
+
+ case PLIST_CHMOD:
+ fprintf(fp, "%cmode %s\n", CMD_CHAR,
+ plist->name ? plist->name : "");
+ break;
+
+ case PLIST_CHOWN:
+ fprintf(fp, "%cowner %s\n", CMD_CHAR,
+ plist->name ? plist->name : "");
+ break;
+
+ case PLIST_CHGRP:
+ fprintf(fp, "%cgroup %s\n", CMD_CHAR,
+ plist->name ? plist->name : "");
+ break;
+
+ case PLIST_COMMENT:
+ fprintf(fp, "%ccomment %s\n", CMD_CHAR, plist->name);
+ break;
+
+ case PLIST_IGNORE:
+ fprintf(fp, "%cignore\n", CMD_CHAR);
+ break;
+
+ case PLIST_NAME:
+ fprintf(fp, "%cname %s\n", CMD_CHAR, plist->name);
+ break;
+
+ default:
+ barf("Unknown command type %d (%s)\n", plist->type, plist->name);
+ break;
+ }
+ plist = plist->next;
+ }
+}
+
+/* Delete the results of a package installation, not the packaging itself */
+int
+delete_package(Boolean ign_err, Package *pkg)
+{
+ PackingList p = pkg->head;
+ char *Where = ".", *last_file = "";
+ Boolean fail = SUCCESS;
+
+ while (p) {
+ if (p->type == PLIST_CWD) {
+ Where = p->name;
+ if (Verbose)
+ printf("(CWD to %s)\n", Where);
+ }
+ else if (p->type == PLIST_UNEXEC) {
+ char cmd[FILENAME_MAX];
+
+ format_cmd(cmd, p->name, Where, last_file);
+ if (Verbose)
+ printf("unexec command: %s\n", cmd);
+ if (!Fake && system(cmd)) {
+ whinge("unexec '%s' failed.", cmd);
+ fail = FAIL;
+ }
+ }
+ else if (p->type == PLIST_IGNORE)
+ p = p->next;
+ else if (p->type == PLIST_FILE) {
+ char full_name[FILENAME_MAX];
+
+ sprintf(full_name, "%s/%s", Where, p->name);
+ if (Verbose)
+ printf("Delete: %s\n", full_name);
+
+ if (!Fake && delete_hierarchy(full_name, ign_err)) {
+ whinge("Unable to completely remove file '%s'", full_name);
+ fail = FAIL;
+ }
+ last_file = p->name;
+ }
+ p = p->next;
+ }
+ return fail;
+}
+
+/* Selectively delete a hierarchy */
+int
+delete_hierarchy(char *dir, Boolean ign_err)
+{
+ char *cp1, *cp2;
+
+ cp1 = cp2 = dir;
+ if (vsystem("%s -r%s %s", REMOVE_CMD, (ign_err ? "f" : ""), dir))
+ return 1;
+ while (cp2) {
+ if ((cp2 = rindex(cp1, '/')) != NULL)
+ *cp2 = '\0';
+ if (!isempty(dir))
+ return 0;
+ if (vsystem("%s %s", RMDIR_CMD, dir) && ign_err)
+ return 1;
+ /* Put it back */
+ if (cp2) {
+ *cp2 = '/';
+ cp1 = cp2 - 1;
+ }
+ }
+ return 0;
+}
diff --git a/usr.sbin/pkg_install/lib/str.c b/usr.sbin/pkg_install/lib/str.c
new file mode 100644
index 0000000..8d68f92
--- /dev/null
+++ b/usr.sbin/pkg_install/lib/str.c
@@ -0,0 +1,85 @@
+#ifndef lint
+static const char *rcsid = "$Id";
+#endif
+
+/*
+ * FreeBSD install - a package for the installation and maintainance
+ * of non-core utilities.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Jordan K. Hubbard
+ * 18 July 1993
+ *
+ * Miscellaneous string utilities.
+ *
+ */
+
+#include "lib.h"
+
+char *
+get_dash_string(char **str)
+{
+ char *s = *str;
+
+ if (*s == '-')
+ *str = copy_string(s + 1);
+ else
+ *str = get_file_contents(s);
+ return *str;
+}
+
+char *
+copy_string(char *str)
+{
+ char *ret;
+
+ if (!str)
+ ret = NULL;
+ else {
+ ret = (char *)malloc(strlen(str) + 1);
+ strcpy(ret, str);
+ }
+ return ret;
+}
+
+/* Return TRUE if 'str' ends in suffix 'suff' */
+Boolean
+suffix(char *str, char *suff)
+{
+ char *idx;
+ Boolean ret = FALSE;
+
+ idx = rindex(str, '.');
+ if (idx && !strcmp(idx + 1, suff))
+ ret = TRUE;
+ return ret;
+}
+
+/* Assuming str has a suffix, brutally murder it! */
+void
+nuke_suffix(char *str)
+{
+ char *idx;
+
+ idx = rindex(str, '.');
+ if (idx)
+ *idx = '\0'; /* Yow! Don't try this on a const! */
+}
+
+/* Lowercase a whole string */
+void
+str_lowercase(char *str)
+{
+ while (*str) {
+ *str = tolower(*str);
+ ++str;
+ }
+}
diff --git a/usr.sbin/pkg_install/pkg b/usr.sbin/pkg_install/pkg
new file mode 100755
index 0000000..f3e53c9
--- /dev/null
+++ b/usr.sbin/pkg_install/pkg
@@ -0,0 +1,158 @@
+#!/usr/local/bin/wish -f
+#$Id: pkg,v 1.6 1993/09/03 23:37:22 rich Exp $
+#
+#$Log: pkg,v $
+# Revision 1.6 1993/09/03 23:37:22 rich
+# warn user if no tar archives are found in the current directory.
+# removed the revision string from the lower text frame.
+#
+# Revision 1.5 1993/09/03 15:48:04 rich
+# glob for .tar.gz, .tar.z and .tar.Z looking for archives
+#
+# Revision 1.4 1993/08/28 15:53:59 rich
+# added version and date info to lower text window.
+#
+# Revision 1.3 1993/08/28 15:47:12 rich
+# filtered out ^Ls in pkg_* output.
+#
+#
+set pkgname ""
+wm title . "Package Installation"
+#--------------------------------------------------------------
+# The top level main window, consisting of a bar of buttons and a list
+# of packages and a description of the current package.
+#--------------------------------------------------------------
+frame .menu -relief raised -borderwidth 1
+frame .frame -borderwidth 4
+
+scrollbar .frame.scroll -relief sunken -command ".frame.list yview"
+listbox .frame.list -yscroll ".frame.scroll set" -relief sunken -setgrid 1
+pack append .frame .frame.scroll {right filly} \
+ .frame.list {left expand fill}
+
+# build the lower window shoing the complete description of a pacage
+frame .f -borderwidth 4
+text .f.t -width 80 -height 20 -yscrollcommand ".f.s set" -relief sunken
+
+# Initially display instructions in this window. Erase the
+# instructions and show the package description when the user clicks
+# on a package.
+#
+.f.t insert end "Double click on a package above to see it's
+complete description here."
+scrollbar .f.s -relief sunken -command ".f.t yview"
+pack append .f .f.s {right filly} .f.t {left expand fill}
+
+bind .frame.list <Double-Button-1> \
+ {foreach i [selection get] {do_description $i}}
+pack append . .menu {top fill} \
+ .f {bottom expand fill} \
+ .frame {bottom expand fill}
+
+#----------------------------------------------------------------
+# Make menu bar:
+#----------------------------------------------------------------
+button .menu.inst -text "Install" \
+ -command "apply_to_pkg \"pkg_add -v\""
+button .menu.dein -text "Deinstall" \
+ -command "apply_to_pkg \"pkg_delete -v\""
+button .menu.installed -text "What is Installed?" \
+ -command "list_pkgs \"pkg_info -I -a |tr ' ' ' '\""
+button .menu.available -text "What can I install?" \
+ -command "list_pkgs \"pkg_info -I -c [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}] |tr ' ' ' '\""
+button .menu.cont -text "Contents?" \
+ -command "global pkgname; apply_to_pkg \"pkg_info -d -v |tr -d ' '\""
+button .menu.quit -text "Quit" -command "destroy ."
+button .menu.help -text "Help" -command "do_help"
+
+pack append .menu \
+ .menu.inst left \
+ .menu.dein left \
+ .menu.installed left \
+ .menu.available left \
+ .menu.cont left \
+ .menu.quit left \
+ .menu.help right
+#-------------------------------------------------------
+# Display the package description.
+#-------------------------------------------------------
+proc list_pkgs {s} {
+ set line ""
+ set f [eval "open {| csh -c \"$s\" } r"]
+ .frame.list delete 0 end
+ while {[gets $f line] > 0} {
+ .frame.list insert end $line
+ }
+ close $f
+}
+
+# display the list of available packages
+set archives [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}]
+if {$pkgname == ""} {
+ .frame.list delete 0 end
+ .frame.list insert end "Warning: no compressed tar archives files found."
+} else {
+ list_pkgs "pkg_info -I -c $archives |tr ' ' ' '"
+}
+
+#-------------------------------------------------------
+# Display the package description.
+#-------------------------------------------------------
+proc do_description {s} {
+ global pkgname
+ regexp {[^ ]*} $s filename
+ set pkgname $filename
+ .f.t delete 0.0 end
+ set cmd "pkg_info -d $filename |tr -d ' '"
+ set f [eval "open {| csh -c \"$cmd\" } r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f]
+ }
+}
+#-------------------------------------------------------
+# package install window.
+#-------------------------------------------------------
+proc do_help {{w .help}} {
+ catch {destroy $w}
+ toplevel $w
+ wm title $w "Help"
+ wm iconname $w "Help"
+ button $w.ok -text OK -command "destroy $w"
+ message $w.t -relief raised -bd 2 \
+ -text "You can install, deinstall and list info on the available packages. To select a package and see it's complete description, press mouse button 1 over the package name. To install a selected package, press the Install button. To exit, press the \"Quit\" button."
+ pack append $w $w.ok {bottom fillx} $w.t {expand fill}
+}
+#-------------------------------------------------------
+# Apply a command to a package.
+#-------------------------------------------------------
+proc apply_to_pkg {s} {
+ global pkgname
+ .f.t delete 0.0 end
+ if {$pkgname == ""} {
+ .f.t insert end "You must double click on a package name first!"
+ } else {
+ .f.t delete 0.0 end
+ .f.t insert end "Running: $s $pkgname\n"
+ set f [eval "open {| $s $pkgname} r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f 64]
+ }
+ }
+}
+#-------------------------------------------------------
+# Invoke an arbitrary command.
+#-------------------------------------------------------
+proc do_command {s} {
+ .f.t delete 0.0 end
+ .f.t insert end "Running: $s\n"
+ set f [eval "open {| $s} r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f 64]
+ }
+}
+# local variables:
+# mode: csh
+# compile-command: ""
+# comment-start: "# "
+# comment-start-skip: "# "
+# end:
diff --git a/usr.sbin/pkg_install/tkpkg b/usr.sbin/pkg_install/tkpkg
new file mode 100755
index 0000000..c4c9273
--- /dev/null
+++ b/usr.sbin/pkg_install/tkpkg
@@ -0,0 +1,161 @@
+#!/usr/local/bin/wish -f
+#$Id: pkg,v 1.1 1993/09/04 17:06:09 jkh Exp $
+#
+#$Log: pkg,v $
+# Revision 1.1 1993/09/04 17:06:09 jkh
+# Added Rich's wish front-end.
+#
+# Revision 1.6 1993/09/03 23:37:22 rich
+# warn user if no tar archives are found in the current directory.
+# removed the revision string from the lower text frame.
+#
+# Revision 1.5 1993/09/03 15:48:04 rich
+# glob for .tar.gz, .tar.z and .tar.Z looking for archives
+#
+# Revision 1.4 1993/08/28 15:53:59 rich
+# added version and date info to lower text window.
+#
+# Revision 1.3 1993/08/28 15:47:12 rich
+# filtered out ^Ls in pkg_* output.
+#
+#
+set pkgname ""
+wm title . "Package Installation"
+#--------------------------------------------------------------
+# The top level main window, consisting of a bar of buttons and a list
+# of packages and a description of the current package.
+#--------------------------------------------------------------
+frame .menu -relief raised -borderwidth 1
+frame .frame -borderwidth 4
+
+scrollbar .frame.scroll -relief sunken -command ".frame.list yview"
+listbox .frame.list -yscroll ".frame.scroll set" -relief sunken -setgrid 1
+pack append .frame .frame.scroll {right filly} \
+ .frame.list {left expand fill}
+
+# build the lower window shoing the complete description of a pacage
+frame .f -borderwidth 4
+text .f.t -width 80 -height 20 -yscrollcommand ".f.s set" -relief sunken
+
+# Initially display instructions in this window. Erase the
+# instructions and show the package description when the user clicks
+# on a package.
+#
+.f.t insert end "Double click on a package above to see it's
+complete description here."
+scrollbar .f.s -relief sunken -command ".f.t yview"
+pack append .f .f.s {right filly} .f.t {left expand fill}
+
+bind .frame.list <Double-Button-1> \
+ {foreach i [selection get] {do_description $i}}
+pack append . .menu {top fill} \
+ .f {bottom expand fill} \
+ .frame {bottom expand fill}
+
+#----------------------------------------------------------------
+# Make menu bar:
+#----------------------------------------------------------------
+button .menu.inst -text "Install" \
+ -command "apply_to_pkg \"pkg_add -v\""
+button .menu.dein -text "Deinstall" \
+ -command "apply_to_pkg \"pkg_delete -v\""
+button .menu.installed -text "What is Installed?" \
+ -command "list_pkgs \"pkg_info -I -a |tr ' ' ' '\""
+button .menu.available -text "What can I install?" \
+ -command "list_pkgs \"pkg_info -I -c [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}] |tr ' ' ' '\""
+button .menu.cont -text "Contents?" \
+ -command "global pkgname; apply_to_pkg \"pkg_info -d -v |tr -d ' '\""
+button .menu.quit -text "Quit" -command "destroy ."
+button .menu.help -text "Help" -command "do_help"
+
+pack append .menu \
+ .menu.inst left \
+ .menu.dein left \
+ .menu.installed left \
+ .menu.available left \
+ .menu.cont left \
+ .menu.quit left \
+ .menu.help right
+#-------------------------------------------------------
+# Display the package description.
+#-------------------------------------------------------
+proc list_pkgs {s} {
+ set line ""
+ set f [eval "open {| csh -c \"$s\" } r"]
+ .frame.list delete 0 end
+ while {[gets $f line] > 0} {
+ .frame.list insert end $line
+ }
+ close $f
+}
+
+# display the list of available packages
+set archives [glob -nocomplain *.{tgz,tar.z,tar.gz,tar.Z}]
+if {$pkgname == ""} {
+ .frame.list delete 0 end
+ .frame.list insert end "Warning: no compressed tar archives files found."
+} else {
+ list_pkgs "pkg_info -I -c $archives |tr ' ' ' '"
+}
+
+#-------------------------------------------------------
+# Display the package description.
+#-------------------------------------------------------
+proc do_description {s} {
+ global pkgname
+ regexp {[^ ]*} $s filename
+ set pkgname $filename
+ .f.t delete 0.0 end
+ set cmd "pkg_info -d $filename |tr -d ' '"
+ set f [eval "open {| csh -c \"$cmd\" } r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f]
+ }
+}
+#-------------------------------------------------------
+# package install window.
+#-------------------------------------------------------
+proc do_help {{w .help}} {
+ catch {destroy $w}
+ toplevel $w
+ wm title $w "Help"
+ wm iconname $w "Help"
+ button $w.ok -text OK -command "destroy $w"
+ message $w.t -relief raised -bd 2 \
+ -text "You can install, deinstall and list info on the available packages. To select a package and see it's complete description, press mouse button 1 over the package name. To install a selected package, press the Install button. To exit, press the \"Quit\" button."
+ pack append $w $w.ok {bottom fillx} $w.t {expand fill}
+}
+#-------------------------------------------------------
+# Apply a command to a package.
+#-------------------------------------------------------
+proc apply_to_pkg {s} {
+ global pkgname
+ .f.t delete 0.0 end
+ if {$pkgname == ""} {
+ .f.t insert end "You must double click on a package name first!"
+ } else {
+ .f.t delete 0.0 end
+ .f.t insert end "Running: $s $pkgname\n"
+ set f [eval "open {| $s $pkgname} r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f 64]
+ }
+ }
+}
+#-------------------------------------------------------
+# Invoke an arbitrary command.
+#-------------------------------------------------------
+proc do_command {s} {
+ .f.t delete 0.0 end
+ .f.t insert end "Running: $s\n"
+ set f [eval "open {| $s} r"]
+ while {![eof $f]} {
+ .f.t insert end [read $f 64]
+ }
+}
+# local variables:
+# mode: csh
+# compile-command: ""
+# comment-start: "# "
+# comment-start-skip: "# "
+# end:
diff --git a/usr.sbin/portmap/Makefile b/usr.sbin/portmap/Makefile
new file mode 100644
index 0000000..1fe7220
--- /dev/null
+++ b/usr.sbin/portmap/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= portmap
+MAN8= portmap.8
+SRCS= portmap.c from_local.c pmap_check.c
+SUBDIR= pmap_set pmap_dump
+
+# -DHOSTS_ACCESS (requires tcpwrapper libraries)
+CFLAGS+=-DCHECK_PORT
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/from_local.c b/usr.sbin/portmap/from_local.c
new file mode 100644
index 0000000..dc5583a
--- /dev/null
+++ b/usr.sbin/portmap/from_local.c
@@ -0,0 +1,147 @@
+ /*
+ * Check if an address belongs to the local system. Adapted from:
+ *
+ * @(#)pmap_svc.c 1.32 91/03/11 Copyright 1984,1990 Sun Microsystems, Inc.
+ * @(#)get_myaddress.c 2.1 88/07/29 4.0 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 or with the express written consent of
+ * Sun Microsystems, Inc.
+ *
+ * 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
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) from_local.c 1.2 93/11/16 21:50:02";
+#endif
+
+#ifdef TEST
+#undef perror
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <syslog.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+/* How many interfaces could there be on a computer? */
+
+#define MAX_LOCAL 16
+static int num_local = -1;
+static struct in_addr addrs[MAX_LOCAL];
+
+/* find_local - find all IP addresses for this host */
+
+find_local()
+{
+ struct ifconf ifc;
+ struct ifreq ifreq;
+ struct ifreq *ifr;
+ struct ifreq *the_end;
+ int sock;
+ char buf[MAX_LOCAL * sizeof(struct ifreq)];
+
+ /* Get list of network interfaces. */
+
+ if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return (0);
+ }
+ ifc.ifc_len = sizeof(buf);
+ ifc.ifc_buf = buf;
+ if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) {
+ perror("SIOCGIFCONF");
+ (void) close(sock);
+ return (0);
+ }
+ /* Get IP address of each active IP network interface. */
+
+ the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+ num_local = 0;
+ for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
+ if (ifr->ifr_addr.sa_family == AF_INET) { /* IP net interface */
+ ifreq = *ifr;
+ if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
+ perror("SIOCGIFFLAGS");
+ } else if (ifreq.ifr_flags & IFF_UP) { /* active interface */
+ if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
+ perror("SIOCGIFADDR");
+ } else {
+ addrs[num_local++] = ((struct sockaddr_in *)
+ & ifreq.ifr_addr)->sin_addr;
+ }
+ }
+ }
+ if (num_local >= MAX_LOCAL)
+ break;
+ /* Support for variable-length addresses. */
+ ifr = (struct ifreq *) ((caddr_t) ifr
+ + ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
+ }
+ (void) close(sock);
+ return (num_local);
+}
+
+/* from_local - determine whether request comes from the local system */
+
+from_local(addr)
+struct sockaddr_in *addr;
+{
+ int i;
+
+ if (num_local == -1 && find_local() == 0)
+ syslog(LOG_ERR, "cannot find any active local network interfaces");
+
+ for (i = 0; i < num_local; i++) {
+ if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]),
+ sizeof(struct in_addr)) == 0)
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+#ifdef TEST
+
+main()
+{
+ char *inet_ntoa();
+ int i;
+
+ find_local();
+ for (i = 0; i < num_local; i++)
+ printf("%s\n", inet_ntoa(addrs[i]));
+}
+
+#endif
diff --git a/usr.sbin/portmap/pmap_check.c b/usr.sbin/portmap/pmap_check.c
new file mode 100644
index 0000000..1d1ed61
--- /dev/null
+++ b/usr.sbin/portmap/pmap_check.c
@@ -0,0 +1,251 @@
+ /*
+ * pmap_check - additional portmap security.
+ *
+ * Always reject non-local requests to update the portmapper tables.
+ *
+ * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the
+ * requests would appear to come from the local system, and nfs export
+ * restrictions could be bypassed.
+ *
+ * Refuse to forward requests to the nfsd process.
+ *
+ * Refuse to forward requests to NIS (YP) daemons; The only exception is the
+ * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial
+ * contact with the NIS server.
+ *
+ * Always allocate an unprivileged port when forwarding a request.
+ *
+ * If compiled with -DCHECK_PORT, require that requests to register or
+ * unregister a privileged port come from a privileged port. This makes it
+ * more difficult to replace a critical service by a trojan.
+ *
+ * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not
+ * authorized by the /etc/hosts.{allow,deny} files. The local system is
+ * always treated as an authorized host. The access control tables are never
+ * consulted for requests from the local system, and are always consulted
+ * for requests from other hosts. Access control is based on IP addresses
+ * only; attempts to map an address to a host name might cause the
+ * portmapper to hang.
+ *
+ * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
+ * Computing Science, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) pmap_check.c 1.6 93/11/21 20:58:59";
+#endif
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <syslog.h>
+#include <netdb.h>
+#include <sys/signal.h>
+
+extern char *inet_ntoa();
+
+#include "pmap_check.h"
+
+/* Explicit #defines in case the include files are not available. */
+
+#define NFSPROG ((u_long) 100003)
+#define MOUNTPROG ((u_long) 100005)
+#define YPXPROG ((u_long) 100069)
+#define YPPROG ((u_long) 100004)
+#define YPPROC_DOMAIN_NONACK ((u_long) 2)
+#define MOUNTPROC_MNT ((u_long) 1)
+
+static void logit();
+static void toggle_verboselog();
+int verboselog = 0;
+int allow_severity = LOG_INFO;
+int deny_severity = LOG_WARNING;
+
+/* A handful of macros for "readability". */
+
+#define good_client(a) hosts_ctl("portmap", "", inet_ntoa(a->sin_addr), "")
+
+#define legal_port(a,p) \
+ (ntohs((a)->sin_port) < IPPORT_RESERVED || (p) >= IPPORT_RESERVED)
+
+#define log_bad_port(addr, proc, prog) \
+ logit(deny_severity, addr, proc, prog, ": request from unprivileged port")
+
+#define log_bad_host(addr, proc, prog) \
+ logit(deny_severity, addr, proc, prog, ": request from unauthorized host")
+
+#define log_bad_owner(addr, proc, prog) \
+ logit(deny_severity, addr, proc, prog, ": request from non-local host")
+
+#define log_no_forward(addr, proc, prog) \
+ logit(deny_severity, addr, proc, prog, ": request not forwarded")
+
+#define log_client(addr, proc, prog) \
+ logit(allow_severity, addr, proc, prog, "")
+
+/* check_startup - additional startup code */
+
+void check_startup()
+{
+
+ /*
+ * Give up root privileges so that we can never allocate a privileged
+ * port when forwarding an rpc request.
+ */
+ if (setuid(1) == -1) {
+ syslog(LOG_ERR, "setuid(1) failed: %m");
+ exit(1);
+ }
+ (void) signal(SIGINT, toggle_verboselog);
+}
+
+/* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
+
+check_default(addr, proc, prog)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+{
+#ifdef HOSTS_ACCESS
+ if (!(from_local(addr) || good_client(addr))) {
+ log_bad_host(addr, proc, prog);
+ return (FALSE);
+ }
+#endif
+ if (verboselog)
+ log_client(addr, proc, prog);
+ return (TRUE);
+}
+
+/* check_privileged_port - additional checks for privileged-port updates */
+
+check_privileged_port(addr, proc, prog, port)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long port;
+{
+#ifdef CHECK_PORT
+ if (!legal_port(addr, port)) {
+ log_bad_port(addr, proc, prog);
+ return (FALSE);
+ }
+#endif
+ return (TRUE);
+}
+
+/* check_setunset - additional checks for update requests */
+
+check_setunset(addr, proc, prog, port)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long port;
+{
+ if (!from_local(addr)) {
+#ifdef HOSTS_ACCESS
+ (void) good_client(addr); /* because of side effects */
+#endif
+ log_bad_owner(addr, proc, prog);
+ return (FALSE);
+ }
+ if (port && !check_privileged_port(addr, proc, prog, port))
+ return (FALSE);
+ if (verboselog)
+ log_client(addr, proc, prog);
+ return (TRUE);
+}
+
+/* check_callit - additional checks for forwarded requests */
+
+check_callit(addr, proc, prog, aproc)
+struct sockaddr_in *addr;
+u_long proc;
+u_long prog;
+u_long aproc;
+{
+#ifdef HOSTS_ACCESS
+ if (!(from_local(addr) || good_client(addr))) {
+ log_bad_host(addr, proc, prog);
+ return (FALSE);
+ }
+#endif
+ if (prog == PMAPPROG || prog == NFSPROG || prog == YPXPROG ||
+ (prog == MOUNTPROG && aproc == MOUNTPROC_MNT) ||
+ (prog == YPPROG && aproc != YPPROC_DOMAIN_NONACK)) {
+ log_no_forward(addr, proc, prog);
+ return (FALSE);
+ }
+ if (verboselog)
+ log_client(addr, proc, prog);
+ return (TRUE);
+}
+
+/* toggle_verboselog - toggle verbose logging flag */
+
+static void toggle_verboselog(sig)
+int sig;
+{
+ (void) signal(sig, toggle_verboselog);
+ verboselog = !verboselog;
+}
+
+/* logit - report events of interest via the syslog daemon */
+
+static void logit(severity, addr, procnum, prognum, text)
+int severity;
+struct sockaddr_in *addr;
+u_long procnum;
+u_long prognum;
+char *text;
+{
+ char *procname;
+ char procbuf[4 * sizeof(u_long)];
+ char *progname;
+ char progbuf[4 * sizeof(u_long)];
+ struct rpcent *rpc;
+ struct proc_map {
+ u_long code;
+ char *proc;
+ };
+ struct proc_map *procp;
+ static struct proc_map procmap[] = {
+ PMAPPROC_CALLIT, "callit",
+ PMAPPROC_DUMP, "dump",
+ PMAPPROC_GETPORT, "getport",
+ PMAPPROC_NULL, "null",
+ PMAPPROC_SET, "set",
+ PMAPPROC_UNSET, "unset",
+ 0, 0,
+ };
+
+ /*
+ * Fork off a process or the portmap daemon might hang while
+ * getrpcbynumber() or syslog() does its thing.
+ */
+
+ if (fork() == 0) {
+
+ /* Try to map program number to name. */
+
+ if (prognum == 0) {
+ progname = "";
+ } else if (rpc = getrpcbynumber((int) prognum)) {
+ progname = rpc->r_name;
+ } else {
+ sprintf(progname = progbuf, "%lu", prognum);
+ }
+
+ /* Try to map procedure number to name. */
+
+ for (procp = procmap; procp->proc && procp->code != procnum; procp++)
+ /* void */ ;
+ if ((procname = procp->proc) == 0)
+ sprintf(procname = procbuf, "%lu", (u_long) procnum);
+
+ /* Write syslog record. */
+
+ syslog(severity, "connect from %s to %s(%s)%s",
+ inet_ntoa(addr->sin_addr), procname, progname, text);
+ exit(0);
+ }
+}
diff --git a/usr.sbin/portmap/pmap_check.h b/usr.sbin/portmap/pmap_check.h
new file mode 100644
index 0000000..2c240df
--- /dev/null
+++ b/usr.sbin/portmap/pmap_check.h
@@ -0,0 +1,11 @@
+/* @(#) pmap_check.h 1.3 93/11/21 16:18:53 */
+
+extern int from_local();
+extern void check_startup();
+extern int check_default();
+extern int check_setunset();
+extern int check_privileged_port();
+extern int check_callit();
+extern int verboselog;
+extern int allow_severity;
+extern int deny_severity;
diff --git a/usr.sbin/portmap/pmap_dump/Makefile b/usr.sbin/portmap/pmap_dump/Makefile
new file mode 100644
index 0000000..0064f28
--- /dev/null
+++ b/usr.sbin/portmap/pmap_dump/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pmap_dump
+NOMAN= noman
+
+.include "${.CURDIR}/../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/pmap_dump/pmap_dump.c b/usr.sbin/portmap/pmap_dump/pmap_dump.c
new file mode 100644
index 0000000..2bddcbb
--- /dev/null
+++ b/usr.sbin/portmap/pmap_dump/pmap_dump.c
@@ -0,0 +1,63 @@
+ /*
+ * pmap_dump - dump portmapper table in format readable by pmap_set
+ *
+ * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
+ * Computing Science, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) pmap_dump.c 1.1 92/06/11 22:53:15";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SYSV40
+#include <netinet/in.h>
+#include <rpc/rpcent.h>
+#else
+#include <netdb.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+
+static char *protoname();
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ struct sockaddr_in addr;
+ register struct pmaplist *list;
+ register struct rpcent *rpc;
+
+ get_myaddress(&addr);
+
+ for (list = pmap_getmaps(&addr); list; list = list->pml_next) {
+ rpc = getrpcbynumber((int) list->pml_map.pm_prog);
+ printf("%10lu %4lu %5s %6lu %s\n",
+ list->pml_map.pm_prog,
+ list->pml_map.pm_vers,
+ protoname(list->pml_map.pm_prot),
+ list->pml_map.pm_port,
+ rpc ? rpc->r_name : "");
+ }
+#undef perror
+ return (fclose(stdout) ? (perror(argv[0]), 1) : 0);
+}
+
+static char *protoname(proto)
+u_long proto;
+{
+ static char buf[BUFSIZ];
+
+ switch (proto) {
+ case IPPROTO_UDP:
+ return ("udp");
+ case IPPROTO_TCP:
+ return ("tcp");
+ default:
+ sprintf(buf, "%lu", proto);
+ return (buf);
+ }
+}
diff --git a/usr.sbin/portmap/pmap_set/Makefile b/usr.sbin/portmap/pmap_set/Makefile
new file mode 100644
index 0000000..987e320
--- /dev/null
+++ b/usr.sbin/portmap/pmap_set/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pmap_set
+NOMAN= noman
+
+.include "${.CURDIR}/../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/portmap/pmap_set/pmap_set.c b/usr.sbin/portmap/pmap_set/pmap_set.c
new file mode 100644
index 0000000..ab82fd5
--- /dev/null
+++ b/usr.sbin/portmap/pmap_set/pmap_set.c
@@ -0,0 +1,70 @@
+ /*
+ * pmap_set - set portmapper table from data produced by pmap_dump
+ *
+ * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and
+ * Computing Science, Eindhoven University of Technology, The Netherlands.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) pmap_set.c 1.1 92/06/11 22:53:16";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SYSV40
+#include <netinet/in.h>
+#endif
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+
+main(argc, argv)
+int argc;
+char **argv;
+{
+ struct sockaddr_in addr;
+ char buf[BUFSIZ];
+ u_long prog;
+ u_long vers;
+ int prot;
+ unsigned port;
+
+ get_myaddress(&addr);
+
+ while (fgets(buf, sizeof(buf), stdin)) {
+ if (parse_line(buf, &prog, &vers, &prot, &port) == 0) {
+ fprintf(stderr, "%s: malformed line: %s", argv[0], buf);
+ return (1);
+ }
+ if (pmap_set(prog, vers, prot, (unsigned short) port) == 0)
+ fprintf(stderr, "not registered: %s", buf);
+ }
+ return (0);
+}
+
+/* parse_line - convert line to numbers */
+
+parse_line(buf, prog, vers, prot, port)
+char *buf;
+u_long *prog;
+u_long *vers;
+int *prot;
+unsigned *port;
+{
+ char proto_name[BUFSIZ];
+
+ if (sscanf(buf, "%lu %lu %s %u", prog, vers, proto_name, port) != 4) {
+ return (0);
+ }
+ if (strcmp(proto_name, "tcp") == 0) {
+ *prot = IPPROTO_TCP;
+ return (1);
+ }
+ if (strcmp(proto_name, "udp") == 0) {
+ *prot = IPPROTO_UDP;
+ return (1);
+ }
+ if (sscanf(proto_name, "%d", prot) == 1) {
+ return (1);
+ }
+ return (0);
+}
diff --git a/usr.sbin/portmap/portmap.8 b/usr.sbin/portmap/portmap.8
new file mode 100644
index 0000000..8edd888
--- /dev/null
+++ b/usr.sbin/portmap/portmap.8
@@ -0,0 +1,112 @@
+.\" Copyright (c) 1987 Sun Microsystems
+.\" Copyright (c) 1990, 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.
+.\"
+.\" @(#)portmap.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.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.
+.It Fl v
+(verbose) enable verbose logging access control checks.
+.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 0000000..6c40795
--- /dev/null
+++ b/usr.sbin/portmap/portmap.c
@@ -0,0 +1,599 @@
+/*-
+ * 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[] = "@(#)portmap.c 8.1 (Berkeley) 6/6/93";
+#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>
+
+#include "pmap_check.h"
+
+void reg_service();
+void reap();
+static void callit();
+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, "dv")) != EOF) {
+ switch (c) {
+
+ case 'd':
+ debugging = 1;
+ break;
+
+ case 'v':
+ verboselog = 1;
+ break;
+
+ default:
+ (void) fprintf(stderr, "usage: %s [-dv]\n", argv[0]);
+ (void) fprintf(stderr, "-d: debugging mode\n");
+ (void) fprintf(stderr, "-v: verbose logging\n");
+ 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);
+ }
+
+ 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);
+
+ /* additional initializations */
+ check_startup();
+ (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;
+
+ /*
+ * Later wrappers change the logging severity on the fly. Reset to
+ * defaults before handling the next request.
+ */
+ allow_severity = LOG_INFO;
+ deny_severity = LOG_WARNING;
+
+ if (debugging)
+ (void) fprintf(stderr, "server: about do a switch\n");
+ switch (rqstp->rq_proc) {
+
+ case PMAPPROC_NULL:
+ /*
+ * Null proc call
+ */
+ /* remote host authorization check */
+ check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
+ 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, &reg))
+ svcerr_decode(xprt);
+ else {
+ /* reject non-local requests, protect priv. ports */
+ if (!check_setunset(svc_getcaller(xprt),
+ rqstp->rq_proc, reg.pm_prog, reg.pm_port)) {
+ ans = 0;
+ goto done;
+ }
+ /*
+ * 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, &reg))
+ svcerr_decode(xprt);
+ else {
+ ans = 0;
+ /* reject non-local requests */
+ if (!check_setunset(svc_getcaller(xprt),
+ rqstp->rq_proc, reg.pm_prog, (u_long) 0))
+ goto done;
+ 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 */
+ /* privileged port check */
+ if (!check_privileged_port(svc_getcaller(xprt),
+ rqstp->rq_proc,
+ reg.pm_prog,
+ pml->pml_map.pm_port)) {
+ ans = 0;
+ break;
+ }
+ 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, &reg))
+ svcerr_decode(xprt);
+ else {
+ /* remote host authorization check */
+ if (!check_default(svc_getcaller(xprt),
+ rqstp->rq_proc,
+ reg.pm_prog)) {
+ ans = 0;
+ goto done;
+ }
+ 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 {
+ /* remote host authorization check */
+ struct pmaplist *p;
+ if (!check_default(svc_getcaller(xprt),
+ rqstp->rq_proc, (u_long) 0)) {
+ p = 0; /* send empty list */
+ } else {
+ p = pmaplist;
+ }
+ if ((!svc_sendreply(xprt, xdr_pmaplist,
+ (caddr_t)&p)) && 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:
+ /* remote host authorization check */
+ check_default(svc_getcaller(xprt), rqstp->rq_proc, (u_long) 0);
+ 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;
+ 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, &a))
+ return;
+ /* host and service access control */
+ if (!check_callit(svc_getcaller(xprt),
+ rqstp->rq_proc, a.rmt_prog, a.rmt_proc))
+ 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 < 0)
+ 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);
+ 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()
+{
+ while (wait3((int *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
+}
diff --git a/usr.sbin/pppd/Makefile b/usr.sbin/pppd/Makefile
new file mode 100644
index 0000000..a0ca52e
--- /dev/null
+++ b/usr.sbin/pppd/Makefile
@@ -0,0 +1,14 @@
+# From: Id: Makefile.bsd,v 1.4 1994/04/20 00:07:50 paulus Exp
+# $Id$
+
+PROG= pppd
+SRCS= main.c magic.c fsm.c lcp.c ipcp.c upap.c chap.c md5.c \
+ auth.c options.c lock.c sys-bsd.c
+MAN8= pppd.8
+BINMODE=4555
+BINOWN= root
+
+LDADD= -lcrypt -lutil
+DPADD= ${LIBCRYPT} ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pppd/RELNOTES b/usr.sbin/pppd/RELNOTES
new file mode 100644
index 0000000..b993de2
--- /dev/null
+++ b/usr.sbin/pppd/RELNOTES
@@ -0,0 +1,295 @@
+ pppd-2.1.1 release notes
+ Paul Mackerras 27 May 1994
+
+This file details the new and changed features in pppd since version 1.3.
+Briefly:
+ - the protocol code has been updated to conform with
+ RFCs 1548, 1549, 1332 and 1334
+ - security has been improved
+ - functionality has been improved in various ways.
+
+
+NEW FEATURES
+
+* The option negotiation automaton has been updated to RFC1548. LCP
+now rejects the Quality Protocol option, since LQR is not implemented
+yet. IPCP now uses the IP-Address option, and falls back to the old
+IP-Addresses option if the IP-Address option is rejected. IPCP also
+uses the new form of the VJ-Compression option.
+
+RFC1548 defines the "passive" option to mean that the automaton
+outputs configure-request packets initially, but does not close down
+if no answer is received. A valid configure-request received will
+restart the negotiation. The "silent" option has been added with the
+old meaning of "passive", i.e. the automaton will not output
+configure-requests until it receives a valid one from the peer.
+
+* More systems are supported: in addition to SunOS 4.x and BSD/Net-2
+derived systems, Ultrix and Linux are supported, thanks to Robert
+Olsson, Per Sundstrom, Michael Callahan and Al Longyear.
+
+* Options can be taken from files as well as the command line. pppd
+reads options from the files /etc/ppp/options and ~/.ppprc before
+looking at the command line, and /etc/ppp/options.<ttyname> after
+interpreting the options on 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 (").
+Backslash (\) quotes the following character. A hash (#) starts a
+comment, which continues until the end of the line. In addition, the
+`file' option causes pppd to read options from a file. pppd will
+report and error and exit if ~/.ppprc or the file given as the
+argument to the `file' option cannot be read by the user who invoked
+pppd.
+
+* On those systems, such as NetBSD, where the serial line speed is
+stored in the termios structure in bits per second (i.e. B9600 ==
+9600), it is possible to set any speed.
+
+* If desired, pppd will output LCP echo-request frames periodically
+while the link is up, and take the link down if no replies are
+received to a user-configurable number of echo-requests. This can be
+used to detect that the serial connection has been broken on those
+systems which don't have hardware modem control lines.
+
+AUTHENTICATION
+
+Previous versions of pppd have provided no control over which IP
+addresses the peer can use. Thus it is possible for the peer to
+impersonate another host on the local network, leading to various
+security holes. In addition, the authentication mechanisms were quite
+weak: if the peer refused to agree to authenticate, pppd would print a
+warning message but still allow the link to come up. The CHAP
+implementation also appeared to be quite broken (has anybody actually
+used it?).
+
+This new version of pppd addresses these problems. My aim has been to
+provide 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 which cannot
+be disabled by users. Thus the new pppd can made setuid-root and run
+by users.
+
+The behaviour where pppd refuses to run unless the /etc/ppp/options
+file is present and readable by pppd is now the default behaviour. If
+you really want pppd to run without the presence of the
+/etc/ppp/options file, you will have to include -DREQ_SYSOPTIONS=0 on
+the compilation command line.
+
+The options related to authentication are:
+
+ auth Require authentication from the peer. If neither
+ +chap or +pap is also given, either CHAP or PAP
+ authentication will be accepted.
+ +chap Require CHAP authentication from the peer.
+ +pap Require PAP authentication from the peer.
+ -chap Don't agree to authenticate ourselves with the peer
+ using CHAP.
+ -pap Don't agree to authenticate ourselves using PAP.
+ +ua <f> Get username and password for authenticating ourselves
+ with the peer using PAP from file <f>.
+ name <n> Use <n> as the local name for authentication.
+ usehostname Use this machine's hostname as the local name for
+ authentication.
+ remotename <n> Use <n> as the name of the peer for authentication.
+ login If the peer authenticates using PAP, check the
+ supplied username and password against the system
+ password database, and make a wtmp entry.
+ user <n> Use <n> as the username for authenticating ourselves
+ using PAP.
+
+The defaults are to agree to authenticate if requested, and to not
+require authentication from the peer. However, pppd will not agree to
+authenticate itself with a particular protocol if it has no secrets
+which could be used to do so.
+
+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 each end can be both a server
+and client, and that different protocols can be used in the two
+directions if desired.
+
+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, server, 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, pppd takes the best match, i.e.
+the match with the fewest wildcards.
+
+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:
+
+ if the `usehostname' option is given,
+ then the local name is the hostname of this machine
+ (with the domain appended, if given)
+
+ else if the `name' option is given,
+ then use the argument of the first `name' option seen
+
+ else if the local IP address is specified with a
+ host name (e.g. `sirius:')
+ then use that host name
+
+ else use the hostname of this machine
+ (with the domain appended, if given)
+
+When authenticating ourselves using PAP, there is also a `username'
+which is the local name by default, but can be set with the `user'
+option or the `+ua' option.
+
+The remote name is set as follows:
+
+ if the `remotename' option is given,
+ then use the argument of the last `remotename' option seen
+
+ else if the remote IP address is specified with a
+ host name (e.g. `avago:')
+ then use that host name
+
+ else the remote name is the null string "".
+
+Secrets are selected from the PAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client ==
+username specified in the PAP authenticate-request, and server ==
+local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == our username, server == remote name.
+
+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 `login' 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.
+
+Secrets are selected from the CHAP secrets file as follows:
+
+- For authenticating the peer, look for a secret with client == name
+specified in the CHAP-Response message, and server == local name.
+
+- For authenticating ourselves to the peer, look for a secret with
+client == local name, and server == name specified in the
+CHAP-Challenge message.
+
+Authentication must be satisfactorily completed before IPCP (or any
+other Network Control Protocol) can be started. If authentication
+fails, pppd will terminated the link (by closing LCP). If IPCP
+negotiates an unacceptable IP address for the remote host, IPCP will
+be closed. IP packets cannot be sent or received until IPCP is
+successfully opened.
+
+(some examples needed here perhaps)
+
+
+ROUTING
+
+Setting the addresses on a ppp interface is sufficient to create a
+host route to the remote end of the link. 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 `defaultroute' option causes pppd to create such a
+default route when IPCP comes up, and delete it when the link is
+terminated.
+
+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 `proxyarp' option causes pppd
+to look for a network interface (an interface supporting broadcast and
+ARP, which is up and not a point-to-point or loopback interface) on
+the same subnet as the remote host. If found, pppd creates a
+permanent, published ARP entry with the IP address of the remote host
+and the hardware address of the network interface found.
+
+
+OTHER NEW AND CHANGED OPTIONS
+
+ modem Use modem control lines (not fully implemented
+ yet)
+ local Don't use modem control lines
+ persist Keep reopening connection (not fully
+ implemented yet)
+
+ lcp-restart <n> Set timeout for LCP retransmissions to <n>
+ seconds (default 3 seconds)
+ lcp-max-terminate <n> Set maximum number of LCP terminate-request
+ transmissions (default 2)
+ lcp-max-configure <n> Set maximum number of LCP configure-request
+ transmissions (default 10)
+ lcp-max-failure <n> Set maximum number of LCP configure-Naks sent
+ before converting to configure-rejects
+ (default 10)
+
+ ipcp-restart <n> Set timeout for IPCP retransmissions to <n>
+ seconds (default 3 seconds)
+ ipcp-max-terminate <n> Set maximum number of IPCP
+ terminate-request transmissions (default 2)
+ ipcp-max-configure <n> Set maximum number of IPCP
+ configure-request transmissions (default 10)
+ ipcp-max-failure <n> Set maximum number of IPCP configure-Naks
+ sent before converting to configure-rejects
+ (default 10)
+
+ upap-restart <n> Set timeout for PAP retransmissions to
+ <n> seconds (default 3 seconds)
+ upap-max-authreq <n> Set maximum number of Authenticate-request
+ retransmissions (default 10)
+
+ chap-restart <n> Set timeout for CHAP retransmissions to
+ <n> seconds (default 3 seconds)
+ chap-max-challenge <n> Set maximum number of CHAP Challenge
+ retransmissions (default 10)
+ chap-interval <n> Set the interval between CHAP rechallenges
+ (default 0, meaning infinity)
+
+The -ua option no longer exists.
+
+
+SOFTWARE RESTRUCTURING
+
+Many of the source files for pppd have changed significantly from
+ppp-1.3, upon which it is based. In particular:
+
+- the macros for system-dependent operations in pppd.h have mostly
+been removed. Instead these operations are performed by procedures in
+sys-bsd.c (for BSD-4.4ish systems like NetBSD, 386BSD, etc.) or
+sys-str.c (for SunOS-based systems using STREAMS). (I got sick of
+having to recompile everything every time I wanted to change one of
+those horrible macros.)
+
+- most of the system-dependent code in main.c has also been removed to
+sys-bsd.c and sys-str.c.
+
+- the option processing code in main.c has been removed to options.c.
+
+- the authentication code in main.c has been removed to auth.c, which
+also contains substantial amounts of new code.
+
+- fsm.c has changed significantly, and lcp.c, ipcp.c, and upap.c have
+changed somewhat. chap.c has also changed significantly.
+
+
+STILL TO DO
+
+* sort out appropriate modem control and implement the persist option
+properly; add an `answer' option for auto-answering a modem.
+
+* add an inactivity timeout and demand dialing.
+
+* implement link quality monitoring.
+
+* implement other network control protocols.
diff --git a/usr.sbin/pppd/args.h b/usr.sbin/pppd/args.h
new file mode 100644
index 0000000..e879838
--- /dev/null
+++ b/usr.sbin/pppd/args.h
@@ -0,0 +1,12 @@
+/*
+ * neat macro from ka9q to "do the right thing" with ansi prototypes
+ * $Id: args.h,v 1.1 1993/11/11 03:54:25 paulus Exp $
+ */
+
+#ifndef __ARGS
+#ifdef __STDC__
+#define __ARGS(x) x
+#else
+#define __ARGS(x) ()
+#endif
+#endif
diff --git a/usr.sbin/pppd/auth.c b/usr.sbin/pppd/auth.c
new file mode 100644
index 0000000..950ef02
--- /dev/null
+++ b/usr.sbin/pppd/auth.c
@@ -0,0 +1,904 @@
+/*
+ * 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.6 1994/05/25 06:25:05 paulus Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.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>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+#ifdef 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
+
+extern char user[];
+extern char passwd[];
+extern char devname[];
+extern char our_name[];
+extern char remote_name[];
+extern char hostname[];
+extern int uselogin;
+extern int usehostname;
+extern int auth_required;
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NPPP];
+static int logged_in;
+static struct wordlist *addresses[NPPP];
+
+/* Bits in auth_pending[] */
+#define UPAP_WITHPEER 1
+#define UPAP_PEER 2
+#define CHAP_WITHPEER 4
+#define CHAP_PEER 8
+
+/* Prototypes */
+void check_access __ARGS((FILE *, char *));
+
+static int login __ARGS((char *, char *, char **, int *));
+static void logout __ARGS((void));
+static int null_login __ARGS((int));
+static int get_upap_passwd __ARGS((void));
+static int have_upap_secret __ARGS((void));
+static int have_chap_secret __ARGS((char *, char *));
+static int scan_authfile __ARGS((FILE *, char *, char *, char *,
+ struct wordlist **, char *));
+static void free_wordlist __ARGS((struct wordlist *));
+
+extern char *crypt __ARGS((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 (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;
+{
+ 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) {
+ phase = PHASE_NETWORK;
+ ipcp_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 CHAP:
+ bit = CHAP_PEER;
+ break;
+ case UPAP:
+ 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);
+ }
+}
+
+/*
+ * 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 CHAP:
+ bit = CHAP_WITHPEER;
+ break;
+ case UPAP:
+ 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) {
+ phase = PHASE_NETWORK;
+ ipcp_open(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 && 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, devname, 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;
+
+ if ((pw = getpwnam(user)) == NULL) {
+ return (UPAP_AUTHNAK);
+ }
+
+ /*
+ * XXX If no passwd, let them login without one.
+ */
+ if (pw->pw_passwd == '\0') {
+ return (UPAP_AUTHACK);
+ }
+
+ epasswd = crypt(passwd, pw->pw_passwd);
+ if (strcmp(epasswd, pw->pw_passwd)) {
+ return (UPAP_AUTHNAK);
+ }
+
+ syslog(LOG_INFO, "user %s logged in", user);
+
+ /*
+ * Write a wtmp entry for this user.
+ */
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ logwtmp(tty, user, ""); /* Add wtmp login entry */
+ logged_in = TRUE;
+
+ return (UPAP_AUTHACK);
+}
+
+/*
+ * logout - Logout the user.
+ */
+static void
+logout()
+{
+ char *tty;
+
+ tty = strrchr(devname, '/');
+ if (tty == NULL)
+ tty = devname;
+ else
+ tty++;
+ 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_long addr;
+{
+ u_long 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_long *)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_long 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/callout.h b/usr.sbin/pppd/callout.h
new file mode 100644
index 0000000..115d01c
--- /dev/null
+++ b/usr.sbin/pppd/callout.h
@@ -0,0 +1,18 @@
+/* Note: This is a copy of /usr/include/sys/callout.h with the c_func */
+/* member of struct callout changed from a pointer to a function of type int*/
+/* to a pointer to a function of type void (generic pointer) as per */
+/* ANSI C */
+
+/* $Id: callout.h,v 1.1 1993/11/11 03:54:25 paulus Exp $ */
+
+#ifndef _ppp_callout_h
+#define _ppp_callout_h
+
+struct callout {
+ int c_time; /* incremental time */
+ caddr_t c_arg; /* argument to routine */
+ void (*c_func)(); /* routine (changed to void (*)() */
+ struct callout *c_next;
+};
+
+#endif /*!_ppp_callout_h*/
diff --git a/usr.sbin/pppd/chap.c b/usr.sbin/pppd/chap.c
new file mode 100644
index 0000000..64f39bc
--- /dev/null
+++ b/usr.sbin/pppd/chap.c
@@ -0,0 +1,823 @@
+/*
+ * 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.3 1994/04/18 04:01:07 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "chap.h"
+#include "md5.h"
+
+chap_state chap[NPPP]; /* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout __ARGS((caddr_t));
+static void ChapResponseTimeout __ARGS((caddr_t));
+static void ChapReceiveChallenge __ARGS((chap_state *, u_char *, int, int));
+static void ChapReceiveResponse __ARGS((chap_state *, u_char *, int, int));
+static void ChapReceiveSuccess __ARGS((chap_state *, u_char *, int, int));
+static void ChapReceiveFailure __ARGS((chap_state *, u_char *, int, int));
+static void ChapSendStatus __ARGS((chap_state *, int));
+static void ChapSendChallenge __ARGS((chap_state *));
+static void ChapSendResponse __ARGS((chap_state *));
+static void ChapGenChallenge __ARGS((chap_state *));
+
+extern double drand48 __ARGS((void));
+extern void srand48 __ARGS((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;
+ srand48((long) time(NULL)); /* joggle random number generator */
+}
+
+
+/*
+ * 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, 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;
+
+ if (cstate->chal_interval != 0)
+ TIMEOUT(ChapRechallenge, (caddr_t) cstate, cstate->chal_interval);
+}
+
+
+/*
+ * 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, CHAP);
+ if (cstate->clientstate != CHAPCS_INITIAL &&
+ cstate->clientstate != CHAPCS_CLOSED)
+ auth_withpeer_fail(unit, 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 (bcmp (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, 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, 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, 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, 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, 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 + DLLHEADERLEN);
+
+ 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, 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 + DLLHEADERLEN);
+
+ 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, 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 + DLLHEADERLEN);
+
+ 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) __ARGS((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;
+}
+
+#ifdef NO_DRAND48
+
+double drand48()
+{
+ return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
+}
+
+void srand48(seedval)
+long seedval;
+{
+ srand((int)seedval);
+}
+
+#endif
diff --git a/usr.sbin/pppd/chap.h b/usr.sbin/pppd/chap.h
new file mode 100644
index 0000000..682ecb8
--- /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.2 1994/04/11 07:13:44 paulus 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 __ARGS((int));
+void ChapAuthWithPeer __ARGS((int, char *, int));
+void ChapAuthPeer __ARGS((int, char *, int));
+void ChapLowerUp __ARGS((int));
+void ChapLowerDown __ARGS((int));
+void ChapInput __ARGS((int, u_char *, int));
+void ChapProtocolReject __ARGS((int));
+int ChapPrintPkt __ARGS((u_char *, int,
+ void (*) __ARGS((void *, char *, ...)), void *));
+
+#define __CHAP_INCLUDE__
+#endif /* __CHAP_INCLUDE__ */
diff --git a/usr.sbin/pppd/fsm.c b/usr.sbin/pppd/fsm.c
new file mode 100644
index 0000000..902ad64
--- /dev/null
+++ b/usr.sbin/pppd/fsm.c
@@ -0,0 +1,773 @@
+/*
+ * 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.3 1994/05/24 11:21:10 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <syslog.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "fsm.h"
+
+extern char *proto_name();
+
+static void fsm_timeout __ARGS((caddr_t));
+static void fsm_rconfreq __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfack __ARGS((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __ARGS((fsm *, int, int, u_char *, int));
+static void fsm_rtermreq __ARGS((fsm *, int));
+static void fsm_rtermack __ARGS((fsm *));
+static void fsm_rcoderej __ARGS((fsm *, u_char *, int));
+static void fsm_sconfreq __ARGS((fsm *, int));
+
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)
+
+int peer_mru[NPPP];
+
+
+/*
+ * 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) /* 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->reqid = -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 Ack? oh well... */
+ 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) /* 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->reqid = -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... */
+ 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:
+ f->state = CLOSED;
+ if( f->callbacks->finished )
+ (*f->callbacks->finished)(f);
+ break;
+ case STOPPING:
+ 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;
+ }
+
+ /*
+ * Make up the request packet
+ */
+ outp = outpacket_buf + DLLHEADERLEN + 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 + DLLHEADERLEN + HEADERLEN)
+ BCOPY(data, outp + DLLHEADERLEN + HEADERLEN, datalen);
+ outlen = datalen + HEADERLEN;
+ MAKEHEADER(outp, f->protocol);
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ output(f->unit, outpacket_buf, outlen + DLLHEADERLEN);
+
+ 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 0000000..a12966b
--- /dev/null
+++ b/usr.sbin/pppd/fsm.h
@@ -0,0 +1,127 @@
+/*
+ * 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.2 1994/04/11 07:18:35 paulus 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 */
+ 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 10 /* Maximum number of nak loops */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init __ARGS((fsm *));
+void fsm_lowerup __ARGS((fsm *));
+void fsm_lowerdown __ARGS((fsm *));
+void fsm_open __ARGS((fsm *));
+void fsm_close __ARGS((fsm *));
+void fsm_input __ARGS((fsm *, u_char *, int));
+void fsm_protreject __ARGS((fsm *));
+void fsm_sdata __ARGS((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 0000000..6c9abb1
--- /dev/null
+++ b/usr.sbin/pppd/ipcp.c
@@ -0,0 +1,1196 @@
+/*
+ * 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.8 1994/05/26 06:37:34 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */
+ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NPPP]; /* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */
+
+extern char ifname[];
+extern char devname[];
+extern int baud_rate;
+
+/* local vars */
+static int cis_received[NPPP]; /* # Conf-Reqs received */
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */
+static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipcp_up __ARGS((fsm *)); /* We're UP */
+static void ipcp_down __ARGS((fsm *)); /* We're DOWN */
+static void ipcp_script __ARGS((fsm *, char *)); /* Run an up/down script */
+
+fsm ipcp_fsm[NPPP]; /* 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_long 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 = 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;
+}
+
+
+/*
+ * 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_long 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_long 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_long 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_long 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(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.neg_addr = 1;
+ try.old_addrs = 0;
+ GETLONG(l, p);
+ ciaddr1 = htonl(l);
+ if (ciaddr1 && go->accept_local)
+ try.ouraddr = ciaddr1;
+ no.neg_addr = 1;
+ break;
+ default:
+ goto bad;
+ }
+ 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_long 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_long 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_long 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 (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ }
+
+ /*
+ * 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 (long), 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 (long), p);
+ tl = ntohl(wo->hisaddr);
+ PUTLONG(tl, p);
+ }
+ }
+
+ 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 = wo->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_long 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_long 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] = devname;
+ argv[3] = strspeed;
+ argv[4] = strlocal;
+ argv[5] = strremote;
+ argv[6] = 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_long 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 0000000..2d1988d
--- /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.3 1994/04/18 04:05:15 paulus 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_long 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 __ARGS((int));
+void ipcp_open __ARGS((int));
+void ipcp_close __ARGS((int));
+void ipcp_lowerup __ARGS((int));
+void ipcp_lowerdown __ARGS((int));
+void ipcp_input __ARGS((int, u_char *, int));
+void ipcp_protrej __ARGS((int));
+int ipcp_printpkt __ARGS((u_char *, int, void (*)(), void *));
diff --git a/usr.sbin/pppd/lcp.c b/usr.sbin/pppd/lcp.c
new file mode 100644
index 0000000..2581518
--- /dev/null
+++ b/usr.sbin/pppd/lcp.c
@@ -0,0 +1,1644 @@
+/*
+ * 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.8 1994/05/30 02:38:49 paulus 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 "ppp.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 <linux/ppp.h>
+#endif
+
+/* global vars */
+fsm lcp_fsm[NPPP]; /* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NPPP]; /* Options that we want to request */
+lcp_options lcp_gotoptions[NPPP]; /* Options that peer ack'd */
+lcp_options lcp_allowoptions[NPPP]; /* Options we allow peer to request */
+lcp_options lcp_hisoptions[NPPP]; /* Options that we ack'd */
+u_long xmit_accm[NPPP][8]; /* extended transmit ACCM */
+
+static u_long lcp_echos_pending = 0; /* Number of outstanding echo msgs */
+static u_long lcp_echo_number = 0; /* ID number of next echo frame */
+static u_long lcp_echo_timer_running = 0; /* TRUE if a timer is running */
+
+u_long lcp_echo_interval = 0;
+u_long lcp_echo_fails = 0;
+
+/*
+ * Callbacks for fsm code. (CI = Configuration Information)
+ */
+static void lcp_resetci __ARGS((fsm *)); /* Reset our CI */
+static int lcp_cilen __ARGS((fsm *)); /* Return length of our CI */
+static void lcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int lcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int lcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int lcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int lcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __ARGS((fsm *)); /* We're UP */
+static void lcp_down __ARGS((fsm *)); /* We're DOWN */
+static void lcp_starting __ARGS((fsm *)); /* We need lower layer up */
+static void lcp_finished __ARGS((fsm *)); /* We need lower layer down */
+static int lcp_extcode __ARGS((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __ARGS((fsm *, u_char *, int));
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup __ARGS((int));
+static void lcp_echo_lowerdown __ARGS((int));
+static void LcpEchoTimeout __ARGS((caddr_t));
+static void lcp_received_echo_reply __ARGS((fsm *, int, u_char *, int));
+static void LcpSendEchoRequest __ARGS((fsm *));
+static void LcpLinkFailure __ARGS((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_warnloops = DEFWARNLOOPS; /* Warn about a loopback this often */
+
+/*
+ * 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 = 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]);
+}
+
+
+/*
+ * 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, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(unit, MTU, 0x00000000, 0, 0);
+ peer_mru[unit] = MTU;
+ 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;
+{
+ fsm_input(&lcp_fsm[unit], p, len);
+}
+
+
+/*
+ * 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);
+ if (len < CILEN_LONG)
+ len = CILEN_LONG;
+ 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] = MTU;
+}
+
+
+/*
+ * 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(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, CHAP, go->chap_mdtype);
+ ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ 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_long 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 != 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, CHAP, go->chap_mdtype);
+ ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, UPAP);
+ 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 cilen, citype, cichar, *next;
+ u_short cishort;
+ u_long cilong;
+ lcp_options no; /* options we've seen Naks for */
+ lcp_options try; /* options to request next time */
+ int looped_back = 0;
+
+ 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 can't cope with our CHAP hash algorithm, we'll have
+ * to stop asking for CHAP. We haven't got any other algorithm.
+ */
+ NAKCICHAP(CI_AUTHTYPE, neg_chap,
+ try.neg_chap = 0;
+ );
+ /*
+ * Peer shouldn't send Nak for UPAP, 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 != LQR)
+ try.neg_lqr = 0;
+ else
+ try.lqr_period = cilong;
+ );
+ /*
+ * Check for a looped-back line.
+ */
+ NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+ try.magicnumber = magic();
+ ++try.numloops;
+ 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.
+ */
+ 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;
+ default:
+ goto bad;
+ }
+ 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;
+ if (looped_back && try.numloops % lcp_warnloops == 0)
+ LCPDEBUG((LOG_INFO, "The line appears to be looped back."));
+ }
+
+ 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_long 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; \
+ 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 != 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, CHAP, go->chap_mdtype);
+ if (!go->neg_chap) {
+ REJCISHORT(CI_AUTHTYPE, neg_upap, UPAP);
+ }
+ 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_long 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 *ucp = inp; /* Pointer to current output char */
+ int l = *lenp; /* Length left */
+
+ /*
+ * 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? */
+ 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 */
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (short), p); /* Backup */
+ PUTSHORT(MINMRU, p); /* 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, "(%lx)", cilong));
+
+ /*
+ * Asyncmap must have set at least the bits
+ * which are set in lcp_allowoptions[unit].asyncmap.
+ */
+ if ((ao->asyncmap & ~cilong) != 0) {
+ orc = CONFNAK;
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (long), p);
+ PUTLONG(ao->asyncmap | cilong, p);
+ }
+ 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)) {
+ 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 == UPAP) {
+ if (!ao->neg_upap || /* we don't want to do PAP */
+ ho->neg_chap || /* or we've already accepted CHAP */
+ cilen != CILEN_SHORT) {
+ LCPDEBUG((LOG_WARNING,
+ "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ ho->neg_upap = 1;
+ break;
+ }
+ if (cishort == CHAP) {
+ if (!ao->neg_chap || /* we don't want to do CHAP */
+ ho->neg_upap || /* or we've already accepted UPAP */
+ cilen != CILEN_CHAP) {
+ LCPDEBUG((LOG_INFO,
+ "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+ orc = CONFREJ;
+ break;
+ }
+ GETCHAR(cichar, p); /* get digest type*/
+ if (cichar != ao->chap_mdtype) {
+ orc = CONFNAK;
+ if( !reject_if_disagree ){
+ DECPTR(sizeof (u_char), p);
+ PUTCHAR(ao->chap_mdtype, p);
+ }
+ break;
+ }
+ ho->chap_mdtype = cichar; /* save md type */
+ ho->neg_chap = 1;
+ break;
+ }
+
+ /*
+ * We don't recognize the protocol they're asking for.
+ * Reject it.
+ */
+ orc = CONFREJ;
+ 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 %lx)", cishort, cilong));
+ if (cishort != LQR) {
+ orc = CONFREJ;
+ break;
+ }
+
+ /*
+ * Check the reporting period.
+ * XXX When should we Nak this, and what with?
+ */
+ 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, "(%lx)", cilong));
+
+ /*
+ * He must have a different magic number.
+ */
+ if (go->neg_magicnumber &&
+ cilong == go->magicnumber) {
+ orc = CONFNAK;
+ DECPTR(sizeof (long), p);
+ cilong = magic(); /* Don't put magic() inside macro! */
+ PUTLONG(cilong, p);
+ 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? */
+ 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 */
+ }
+ if (ucp != cip) /* Need to move CI? */
+ BCOPY(cip, ucp, cilen); /* Move it */
+ INCPTR(cilen, ucp); /* Update output pointer */
+ }
+
+ /*
+ * If we wanted to send additional NAKs (for unsent CIs), the
+ * code would go here. This must be done with care since it might
+ * require a longer packet than we received. At present there
+ * are no cases where we want to ask the peer to negotiate an option.
+ */
+
+ *lenp = ucp - inp; /* Compute output length */
+ 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: MTU)),
+ (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): MTU),
+ (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 */
+ 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);
+ ipcp_lowerdown(f->unit);
+ ChapLowerDown(f->unit);
+ upap_lowerdown(f->unit);
+
+ sifdown(f->unit);
+ ppp_send_config(f->unit, MTU, 0xffffffff, 0, 0);
+ ppp_recv_config(f->unit, MTU, 0x00000000, 0, 0);
+ peer_mru[f->unit] = MTU;
+
+ 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) __ARGS((void *, char *, ...));
+ void *arg;
+{
+ int code, id, len, olen;
+ u_char *pstart, *optend;
+ u_short cishort;
+ u_long 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 UPAP:
+ printer(arg, "upap");
+ break;
+ case 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 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_lowerdown(f->unit); /* Reset connection */
+ }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (f)
+ fsm *f;
+{
+ u_long delta;
+#ifdef __linux__
+ struct ppp_ddinfo ddinfo;
+ u_long latest;
+/*
+ * Read the time since the last packet was received.
+ */
+ if (ioctl (fd, PPPIOCGTIME, &ddinfo) < 0) {
+ syslog (LOG_ERR, "ioctl(PPPIOCGTIME): %m");
+ die (1);
+ }
+/*
+ * Choose the most recient frame received. It may be an IP or NON-IP frame.
+ */
+ latest = ddinfo.nip_rjiffies < ddinfo.ip_rjiffies ? ddinfo.nip_rjiffies
+ : ddinfo.ip_rjiffies;
+/*
+ * 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 = (lcp_echo_interval * HZ) - latest;
+ if (delta < HZ || latest < 0L) {
+ LcpSendEchoRequest (f);
+ delta = lcp_echo_interval * HZ;
+ }
+ delta /= HZ;
+
+#else /* Other implementations do not have ability to find delta */
+ LcpSendEchoRequest (f);
+ delta = lcp_echo_interval;
+#endif
+
+/*
+ * Start the timer for the next interval.
+ */
+ assert (lcp_echo_timer_running==0);
+ TIMEOUT (LcpEchoTimeout, (caddr_t) f, 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_long magic;
+
+ /* Check the magic number - don't count replies from ourselves. */
+ if (len < CILEN_LONG)
+ return;
+ GETLONG(magic, inp);
+ if (lcp_gotoptions[f->unit].neg_magicnumber
+ && magic == lcp_gotoptions[f->unit].magicnumber)
+ 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_long 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);
+}
+
+/*
+ * 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;
+ }
+}
diff --git a/usr.sbin/pppd/lcp.h b/usr.sbin/pppd/lcp.h
new file mode 100644
index 0000000..0499a7c
--- /dev/null
+++ b/usr.sbin/pppd/lcp.h
@@ -0,0 +1,87 @@
+/*
+ * 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.4 1994/05/24 11:22:28 paulus 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_long asyncmap; /* Value of async map */
+ u_long magicnumber;
+ int numloops; /* Number of loops during magic number neg. */
+ u_long lqr_period; /* Reporting period for link quality */
+} 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_long 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 __ARGS((int));
+void lcp_open __ARGS((int));
+void lcp_close __ARGS((int));
+void lcp_lowerup __ARGS((int));
+void lcp_lowerdown __ARGS((int));
+void lcp_input __ARGS((int, u_char *, int));
+void lcp_protrej __ARGS((int));
+void lcp_sprotrej __ARGS((int, u_char *, int));
+int lcp_printpkt __ARGS((u_char *, int,
+ void (*) __ARGS((void *, char *, ...)), void *));
+
+extern int lcp_warnloops; /* Warn about a loopback this often */
+#define DEFWARNLOOPS 10 /* Default value for above */
diff --git a/usr.sbin/pppd/lock.c b/usr.sbin/pppd/lock.c
new file mode 100644
index 0000000..0fbbef3
--- /dev/null
+++ b/usr.sbin/pppd/lock.c
@@ -0,0 +1,122 @@
+/*
+ * lock.c - lock/unlock the serial device.
+ *
+ * This code is derived from chat.c.
+ */
+
+static char rcsid[] = "$Id: lock.c,v 1.1 1994/04/18 23:41:52 paulus Exp $";
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+
+#ifdef sun
+# if defined(SUNOS) && SUNOS >= 41
+# ifndef HDB
+# define HDB
+# endif
+# endif
+#endif
+
+#ifndef LOCK_DIR
+# ifdef __NetBSD__
+# define PIDSTRING
+# define LOCK_PREFIX "/var/spool/lock/LCK.."
+# else
+# ifdef HDB
+# define PIDSTRING
+# define LOCK_PREFIX "/usr/spool/locks/LCK.."
+# else /* HDB */
+# define LOCK_PREFIX "/usr/spool/uucp/LCK.."
+# endif /* HDB */
+# endif
+#endif /* LOCK_DIR */
+
+static char *lock_file;
+
+/*
+ * Create a lock file for the named lock device
+ */
+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 */
+#ifdef PIDSTRING
+ n = read(fd, hdb_lock_buffer, 11);
+ if (n > 0) {
+ hdb_lock_buffer[n] = 0;
+ pid = atoi(hdb_lock_buffer);
+ }
+#else
+ n = read(fd, &pid, sizeof(pid));
+#endif
+ 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;
+ }
+
+# ifdef PIDSTRING
+ sprintf(hdb_lock_buffer, "%10d\n", getpid());
+ write(fd, hdb_lock_buffer, 11);
+# else
+ pid = getpid();
+ write(fd, &pid, sizeof pid);
+# endif
+
+ close(fd);
+ return 0;
+}
+
+/*
+ * Remove our lockfile
+ */
+unlock()
+{
+ if (lock_file) {
+ unlink(lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ }
+}
+
diff --git a/usr.sbin/pppd/magic.c b/usr.sbin/pppd/magic.c
new file mode 100644
index 0000000..20dfd6f
--- /dev/null
+++ b/usr.sbin/pppd/magic.c
@@ -0,0 +1,70 @@
+/*
+ * 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 1993/11/11 03:54:25 paulus Exp $";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "magic.h"
+
+
+static u_long next; /* Next value to return */
+
+extern u_long gethostid __ARGS((void));
+extern long random __ARGS((void));
+extern void srandom __ARGS((int));
+
+
+/*
+ * magic_init - Initialize the magic number generator.
+ *
+ * Computes first magic number and seed for random number generator.
+ * Attempts to compute a random number seed which will not repeat.
+ * The current method uses the current hostid and current time.
+ */
+void magic_init()
+{
+ struct timeval tv;
+
+ next = gethostid();
+ if (gettimeofday(&tv, NULL)) {
+ perror("gettimeofday");
+ exit(1);
+ }
+ next ^= (u_long) tv.tv_sec ^ (u_long) tv.tv_usec;
+
+ srandom((int) next);
+}
+
+
+/*
+ * magic - Returns the next magic number.
+ */
+u_long magic()
+{
+ u_long m;
+
+ m = next;
+ next = (u_long) random();
+ return (m);
+}
diff --git a/usr.sbin/pppd/magic.h b/usr.sbin/pppd/magic.h
new file mode 100644
index 0000000..d41aa39
--- /dev/null
+++ b/usr.sbin/pppd/magic.h
@@ -0,0 +1,24 @@
+/*
+ * 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 1993/11/11 03:54:25 paulus Exp $
+ */
+#include "args.h"
+
+void magic_init __ARGS((void)); /* Initialize the magic number generator */
+u_long magic __ARGS((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 0000000..1e1397e
--- /dev/null
+++ b/usr.sbin/pppd/main.c
@@ -0,0 +1,1445 @@
+/*
+ * 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.13 1994/05/27 01:02:14 paulus Exp $";
+#endif
+
+#define SETSID
+
+#include <stdio.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/wait.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
+
+#ifdef SGTTY
+#include <sgtty.h>
+#else
+#ifndef sun
+#include <sys/ioctl.h>
+#endif
+#include <termios.h>
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <net/if.h>
+
+#include "callout.h"
+#include "ppp.h"
+#include "magic.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+
+#include "pppd.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+
+
+#ifndef TRUE
+#define TRUE (1)
+#endif /*TRUE*/
+
+#ifndef FALSE
+#define FALSE (0)
+#endif /*FALSE*/
+
+#ifdef PIDPATH
+static char *pidpath = PIDPATH; /* filename in which pid will be stored */
+#else
+static char *pidpath = _PATH_PIDFILE;
+#endif /* PIDFILE */
+
+/* interface vars */
+char ifname[IFNAMSIZ]; /* Interface name */
+int ifunit; /* Interface unit number */
+
+char *progname; /* Name of this program */
+char hostname[MAXNAMELEN]; /* Our hostname */
+char our_name[MAXNAMELEN];
+char remote_name[MAXNAMELEN];
+static char pidfilename[MAXPATHLEN];
+
+static pid_t pid; /* Our pid */
+static pid_t pgrpid; /* Process Group ID */
+uid_t uid; /* Our real user-id */
+
+char devname[MAXPATHLEN] = "/dev/tty"; /* Device name */
+int default_device = TRUE; /* use default device (stdin/out) */
+
+int fd = -1; /* Device file descriptor */
+int s; /* Socket file descriptor */
+
+int phase; /* where the link is at */
+
+#ifdef SGTTY
+static struct sgttyb initsgttyb; /* Initial TTY sgttyb */
+#else
+static struct termios inittermios; /* Initial TTY termios */
+#endif
+
+static int initfdflags = -1; /* Initial file descriptor flags */
+
+static int restore_term; /* 1 => we've munged the terminal */
+
+u_char outpacket_buf[MTU+DLLHEADERLEN]; /* buffer for outgoing packet */
+static u_char inpacket_buf[MTU+DLLHEADERLEN]; /* buffer for incoming packet */
+
+int hungup; /* terminal has been hung up */
+static int n_children; /* # child processes still running */
+
+/* configured variables */
+
+int debug = 0; /* Debug flag */
+int kdebugflag = 0; /* Kernel debugging flag */
+char user[MAXNAMELEN]; /* username for PAP */
+char passwd[MAXSECRETLEN]; /* password for PAP */
+char *connector = NULL; /* "connect" command */
+char *disconnector = NULL; /* "disconnect" command */
+int inspeed = 0; /* Input/Output speed requested */
+int baud_rate; /* bits/sec currently used */
+u_long netmask = 0; /* netmask to use on ppp interface */
+int crtscts = 0; /* use h/w flow control */
+int nodetach = 0; /* don't fork */
+int modem = 0; /* use modem control lines */
+int auth_required = 0; /* require peer to authenticate */
+int defaultroute = 0; /* assign default route through interface */
+int proxyarp = 0; /* set entry in arp table */
+int persist = 0; /* re-initiate on termination */
+int answer = 0; /* wait for incoming call */
+int uselogin = 0; /* check PAP info against /etc/passwd */
+int lockflag = 0; /* lock the serial device */
+
+
+/* prototypes */
+static void hup __ARGS((int));
+static void intr __ARGS((int));
+static void term __ARGS((int));
+static void alrm __ARGS((int));
+static void io __ARGS((int));
+static void chld __ARGS((int));
+static void incdebug __ARGS((int));
+static void nodebug __ARGS((int));
+void establish_ppp __ARGS((void));
+
+void reap_kids __ARGS((void));
+void cleanup __ARGS((int, caddr_t));
+void die __ARGS((int));
+void novm __ARGS((char *));
+
+void log_packet __ARGS((u_char *, int, char *));
+void format_packet __ARGS((u_char *, int,
+ void (*) (void *, char *, ...), void *));
+void pr_log __ARGS((void *, char *, ...));
+
+extern char *ttyname __ARGS((int));
+extern char *getlogin __ARGS((void));
+
+/*
+ * 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)();
+ char *name;
+} prottbl[] = {
+ { LCP, lcp_init, lcp_input, lcp_protrej, lcp_printpkt, "LCP" },
+ { IPCP, ipcp_init, ipcp_input, ipcp_protrej, ipcp_printpkt, "IPCP" },
+ { UPAP, upap_init, upap_input, upap_protrej, upap_printpkt, "PAP" },
+ { CHAP, ChapInit, ChapInput, ChapProtocolReject, ChapPrintPkt, "CHAP" },
+};
+
+#define N_PROTO (sizeof(prottbl) / sizeof(prottbl[0]))
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int mask, i;
+ struct sigaction sa;
+ struct cmd *cmdp;
+ FILE *pidfile;
+ char *p;
+ struct passwd *pw;
+
+ p = ttyname(0);
+ if (p)
+ strcpy(devname, p);
+
+ if (gethostname(hostname, MAXNAMELEN) < 0 ) {
+ perror("couldn't get hostname");
+ die(1);
+ }
+ hostname[MAXNAMELEN-1] = 0;
+
+ pid = getpid();
+ uid = getuid();
+
+ if (!ppp_available()) {
+ fprintf(stderr, "Sorry - PPP is not available on this system\n");
+ 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();
+
+ /*
+ * Initialize syslog system and magic number package.
+ */
+#if !defined(ultrix)
+ openlog("pppd", LOG_PID | LOG_NDELAY, LOG_PPP);
+ setlogmask(LOG_UPTO(LOG_INFO));
+#else
+ openlog("pppd", LOG_PID);
+#define LOG_UPTO(x) (x)
+#define setlogmask(x) (x)
+#endif
+ if (debug)
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+
+ magic_init();
+
+ 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);
+
+#ifdef SETSID
+ /*
+ * Make sure we can set the serial device to be our controlling terminal.
+ */
+ if (default_device) {
+ /*
+ * No device name was specified:
+ * we are in the device's session already.
+ */
+ if ((pgrpid = getpgrp(0)) < 0) {
+ syslog(LOG_ERR, "getpgrp(0): %m");
+ die(1);
+ }
+
+ } else {
+ /*
+ * Not default device: make sure we're not a process group leader,
+ * then become session leader of a new session (so we can make
+ * our device its controlling terminal and thus get SIGHUPs).
+ */
+ if (!nodetach) {
+ /* fork so we're not a process group leader */
+ if (pid = fork()) {
+ exit(0); /* parent is finished */
+ }
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
+ }
+ pid = getpid(); /* otherwise pid is 0 in child */
+ } else {
+ /*
+ * try to put ourself into our parent's process group,
+ * so we're not a process group leader
+ */
+ if (setpgrp(pid, getppid()) < 0)
+ syslog(LOG_WARNING, "setpgrp: %m");
+ }
+
+ /* create new session */
+ if ((pgrpid = setsid()) < 0) {
+ syslog(LOG_ERR, "setsid(): %m");
+ die(1);
+ }
+ }
+#endif
+
+ if (lockflag && !default_device)
+ if (lock(devname) < 0)
+ die(1);
+
+ /* Get an internet socket for doing socket ioctl's on. */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ syslog(LOG_ERR, "socket : %m");
+ die(1);
+ }
+
+ /*
+ * 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, SIGALRM);
+ sigaddset(&mask, SIGIO);
+ sigaddset(&mask, SIGCHLD);
+#ifdef STREAMS
+ sigaddset(&mask, SIGPOLL);
+#endif
+
+#define SIGNAL(s, handler) { \
+ sa.sa_handler = handler; \
+ if (sigaction(s, &sa, NULL) < 0) { \
+ syslog(LOG_ERR, "sigaction(%d): %m", s); \
+ die(1); \
+ } \
+ }
+
+ sa.sa_mask = mask;
+ sa.sa_flags = 0;
+ SIGNAL(SIGHUP, hup); /* Hangup */
+ SIGNAL(SIGINT, intr); /* Interrupt */
+ SIGNAL(SIGTERM, term); /* Terminate */
+ SIGNAL(SIGALRM, alrm); /* Timeout */
+ SIGNAL(SIGIO, io); /* Input available */
+ SIGNAL(SIGCHLD, chld); /* Death of child process */
+#ifdef STREAMS
+ SIGNAL(SIGPOLL, io); /* Input available */
+#endif
+
+ signal(SIGUSR1, incdebug); /* Increment debug flag */
+ signal(SIGUSR2, nodebug); /* Reset debug flag */
+
+ /*
+ * Block SIGIOs and SIGPOLLs for now
+ */
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGIO);
+#ifdef STREAMS
+ sigaddset(&mask, SIGPOLL);
+#endif
+ sigprocmask(SIG_BLOCK, &mask, NULL);
+
+ /*
+ * Open the serial device and set it up to be the ppp interface.
+ */
+ if ((fd = open(devname, O_RDWR /*| O_NDELAY*/)) < 0) {
+ syslog(LOG_ERR, "open(%s): %m", devname);
+ die(1);
+ }
+ hungup = 0;
+
+#ifdef TIOCSCTTY
+ /* set device to be controlling tty */
+ if (!default_device && ioctl(fd, TIOCSCTTY) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSCTTY): %m");
+ die(1);
+ }
+#endif /* TIOCSCTTY */
+
+ /* run connection script */
+ if (connector) {
+ 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, "could not set up connection");
+ setdtr(fd, FALSE);
+ die(1);
+ }
+
+ syslog(LOG_INFO, "Connected...");
+ 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", pidpath, ifname);
+ if ((pidfile = fopen(pidfilename, "w")) != NULL) {
+ fprintf(pidfile, "%d\n", pid);
+ (void) fclose(pidfile);
+ } else {
+ syslog(LOG_ERR, "unable to create pid file: %m");
+ pidfilename[0] = 0;
+ }
+
+ /*
+ * Set process group of device to our process group so we can get
+ * SIGIOs and SIGHUPs.
+ */
+#ifdef SETSID
+ if (default_device) {
+ int id = tcgetpgrp(fd);
+ if (id != pgrpid) {
+ syslog(LOG_WARNING, "warning: not in tty's process group");
+ }
+ } else {
+ if (tcsetpgrp(fd, pgrpid) < 0) {
+ syslog(LOG_ERR, "tcsetpgrp(): %m");
+ die(1);
+ }
+ }
+#else
+ /* set process group on tty so we get SIGIO's */
+ if (ioctl(fd, TIOCSPGRP, &pgrpid) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSPGRP): %m");
+ die(1);
+ }
+#endif
+
+ /*
+ * Record initial device flags, then set device to cause SIGIO
+ * signals to be generated.
+ */
+ if ((initfdflags = fcntl(fd, F_GETFL)) == -1) {
+ syslog(LOG_ERR, "fcntl(F_GETFL): %m");
+ die(1);
+ }
+
+#ifdef _linux_ /* This is a kludge for Linux. FIXME !!! -- later. */
+#undef FASYNC
+#define FASYNC 0
+#endif
+
+ if (fcntl(fd, F_SETFL, FNDELAY | FASYNC) == -1) {
+ syslog(LOG_ERR, "fcntl(F_SETFL, FNDELAY | FASYNC): %m");
+ die(1);
+ }
+
+ /*
+ * Block all signals, start opening the connection, and wait for
+ * incoming signals (reply, timeout, etc.).
+ */
+ syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devname);
+ sigprocmask(SIG_BLOCK, &mask, NULL); /* Block signals now */
+ lcp_lowerup(0); /* XXX Well, sort of... */
+ lcp_open(0); /* Start protocol */
+ for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; )
+ sigpause(0); /* Wait for next signal */
+
+ /*
+ * Run disconnector script, if requested
+ */
+ if (disconnector) {
+ if (device_script(disconnector, fd, fd) < 0) {
+ syslog(LOG_WARNING, "disconnect script failed");
+ die(1);
+ }
+
+ syslog(LOG_INFO, "Disconnected...");
+ }
+
+ quit();
+}
+
+#if B9600 == 9600
+/*
+ * XXX assume speed_t values numerically equal bits per second
+ * (so we can ask for any speed).
+ */
+#define translate_speed(bps) (bps)
+#define baud_rate_of(speed) (speed)
+
+#else
+/*
+ * List of valid speeds.
+ */
+struct speed {
+ int speed_int, speed_val;
+} speeds[] = {
+#ifdef B50
+ { 50, B50 },
+#endif
+#ifdef B75
+ { 75, B75 },
+#endif
+#ifdef B110
+ { 110, B110 },
+#endif
+#ifdef B134
+ { 134, B134 },
+#endif
+#ifdef B150
+ { 150, B150 },
+#endif
+#ifdef B200
+ { 200, B200 },
+#endif
+#ifdef B300
+ { 300, B300 },
+#endif
+#ifdef B600
+ { 600, B600 },
+#endif
+#ifdef B1200
+ { 1200, B1200 },
+#endif
+#ifdef B1800
+ { 1800, B1800 },
+#endif
+#ifdef B2000
+ { 2000, B2000 },
+#endif
+#ifdef B2400
+ { 2400, B2400 },
+#endif
+#ifdef B3600
+ { 3600, B3600 },
+#endif
+#ifdef B4800
+ { 4800, B4800 },
+#endif
+#ifdef B7200
+ { 7200, B7200 },
+#endif
+#ifdef B9600
+ { 9600, B9600 },
+#endif
+#ifdef B19200
+ { 19200, B19200 },
+#endif
+#ifdef B38400
+ { 38400, B38400 },
+#endif
+#ifdef EXTA
+ { 19200, EXTA },
+#endif
+#ifdef EXTB
+ { 38400, EXTB },
+#endif
+#ifdef B57600
+ { 57600, B57600 },
+#endif
+#ifdef B115200
+ { 115200, B115200 },
+#endif
+ { 0, 0 }
+};
+
+/*
+ * Translate from bits/second to a speed_t.
+ */
+int
+translate_speed(bps)
+ int bps;
+{
+ struct speed *speedp;
+
+ if (bps == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (bps == speedp->speed_int)
+ return speedp->speed_val;
+ syslog(LOG_WARNING, "speed %d not supported", bps);
+ return 0;
+}
+
+/*
+ * Translate from a speed_t to bits/second.
+ */
+int
+baud_rate_of(speed)
+ int speed;
+{
+ struct speed *speedp;
+
+ if (speed == 0)
+ return 0;
+ for (speedp = speeds; speedp->speed_int; speedp++)
+ if (speed == speedp->speed_val)
+ return speedp->speed_int;
+ return 0;
+}
+#endif
+
+/*
+ * 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.
+ */
+set_up_tty(fd, local)
+ int fd, local;
+{
+#ifndef SGTTY
+ int speed, x;
+ struct termios tios;
+
+ if (tcgetattr(fd, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ die(1);
+ }
+
+ if (!restore_term)
+ inittermios = tios;
+
+#ifdef CRTSCTS
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL | CRTSCTS);
+ if (crtscts == 1)
+ tios.c_cflag |= CRTSCTS;
+#else
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+#endif /* 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 */
+ }
+
+ speed = translate_speed(inspeed);
+ if (speed) {
+ cfsetospeed(&tios, speed);
+ cfsetispeed(&tios, speed);
+ } else {
+ speed = cfgetospeed(&tios);
+ }
+
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ die(1);
+ }
+
+#ifdef ultrix
+ x = 0;
+ if (ioctl(fd, (crtscts || modem)? TIOCMODEM: TIOCNMODEM, &x) < 0)
+ syslog(LOG_WARNING, "TIOC(N)MODEM: %m");
+ if (ioctl(fd, (local || !modem)? TIOCNCAR: TIOCCAR) < 0)
+ syslog(LOG_WARNING, "TIOC(N)CAR: %m");
+#endif
+
+#else /* SGTTY */
+ int speed;
+ struct sgttyb sgttyb;
+
+ /*
+ * Put the tty in raw mode.
+ */
+ if (ioctl(fd, TIOCGETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETP): %m");
+ die(1);
+ }
+
+ if (!restore_term)
+ initsgttyb = sgttyb;
+
+ sgttyb.sg_flags = RAW | ANYP;
+ speed = translate_speed(inspeed);
+ if (speed)
+ sgttyb.sg_ispeed = speed;
+ else
+ speed = sgttyb.sg_ispeed;
+
+ if (ioctl(fd, TIOCSETP, &sgttyb) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETP): %m");
+ die(1);
+ }
+#endif
+
+ baud_rate = baud_rate_of(speed);
+ restore_term = TRUE;
+}
+
+/*
+ * 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);
+}
+
+
+/*
+ * quit - Clean up state and exit.
+ */
+void
+quit()
+{
+ die(0);
+}
+
+/*
+ * 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) {
+ /* drop dtr to hang up */
+ if (modem)
+ setdtr(fd, FALSE);
+
+ if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+ syslog(LOG_WARNING, "fcntl(F_SETFL, fdflags): %m");
+ initfdflags = -1;
+
+ disestablish_ppp();
+
+ if (restore_term) {
+#ifndef SGTTY
+ if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0)
+ syslog(LOG_WARNING, "tcsetattr: %m");
+#else
+ if (ioctl(fd, TIOCSETP, &initsgttyb) < 0)
+ syslog(LOG_WARNING, "ioctl(TIOCSETP): %m");
+#endif
+ }
+
+ close(fd);
+ fd = -1;
+ }
+
+ if (pidfilename[0] != 0 && unlink(pidfilename) < 0)
+ syslog(LOG_WARNING, "unable to unlink pid file: %m");
+ pidfilename[0] = 0;
+
+ if (lockflag && !default_device)
+ unlock();
+}
+
+
+static struct callout *callout = NULL; /* Callout list */
+static struct timeval schedtime; /* Time last timeout was set */
+
+/*
+ * 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 itimerval itv;
+ struct callout *newp, **oldpp;
+
+ MAINDEBUG((LOG_DEBUG, "Timeout %x:%x in %d seconds.",
+ (int) func, (int) 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;
+
+ /*
+ * Find correct place to link it in and decrement its time by the
+ * amount of time used by preceding timeouts.
+ */
+ for (oldpp = &callout;
+ *oldpp && (*oldpp)->c_time <= time;
+ oldpp = &(*oldpp)->c_next)
+ time -= (*oldpp)->c_time;
+ newp->c_time = time;
+ newp->c_next = *oldpp;
+ if (*oldpp)
+ (*oldpp)->c_time -= time;
+ *oldpp = newp;
+
+ /*
+ * If this is now the first callout then we have to set a new
+ * itimer.
+ */
+ if (callout == newp) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in timeout.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ }
+}
+
+
+/*
+ * 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 %x:%x.", (int) func, (int) arg));
+
+ /*
+ * If the first callout is unscheduled then we have to set a new
+ * itimer.
+ */
+ if (callout &&
+ callout->c_func == func &&
+ callout->c_arg == arg)
+ reschedule = 1;
+
+ /*
+ * Find first matching timeout. Add its time to the next timeouts
+ * time.
+ */
+ for (copp = &callout; *copp; copp = &(*copp)->c_next)
+ if ((*copp)->c_func == func &&
+ (*copp)->c_arg == arg) {
+ freep = *copp;
+ *copp = freep->c_next;
+ if (*copp)
+ (*copp)->c_time += freep->c_time;
+ (void) free((char *) freep);
+ break;
+ }
+
+ if (reschedule) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec =
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout ? callout->c_time : 0;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in untimeout.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ }
+}
+
+
+/*
+ * adjtimeout - Decrement the first timeout by the amount of time since
+ * it was scheduled.
+ */
+void
+adjtimeout()
+{
+ struct timeval tv;
+ int timediff;
+
+ if (callout == NULL)
+ return;
+ /*
+ * Make sure that the clock hasn't been warped dramatically.
+ * Account for recently expired, but blocked timer by adding
+ * small fudge factor.
+ */
+ if (gettimeofday(&tv, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ timediff = tv.tv_sec - schedtime.tv_sec;
+ if (timediff < 0 ||
+ timediff > callout->c_time + 1)
+ return;
+
+ callout->c_time -= timediff; /* OK, Adjust time */
+}
+
+
+/*
+ * hup - Catch SIGHUP signal.
+ *
+ * Indicates that the physical layer has been disconnected.
+ */
+static void
+hup(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Hangup (SIGHUP)");
+
+ hungup = 1; /* they hung up on us! */
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_lowerdown(0); /* Reset connection */
+ quit(); /* and die */
+}
+
+
+/*
+ * term - Catch SIGTERM signal.
+ *
+ * Indicates that we should initiate a graceful disconnect and exit.
+ */
+static void
+term(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Terminating link.");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
+}
+
+
+/*
+ * intr - Catch SIGINT signal (DEL/^C).
+ *
+ * Indicates that we should initiate a graceful disconnect and exit.
+ */
+static void
+intr(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Interrupt received: terminating link");
+ persist = 0; /* don't try to restart */
+ adjtimeout(); /* Adjust timeouts */
+ lcp_close(0); /* Close connection */
+}
+
+
+/*
+ * alrm - Catch SIGALRM signal.
+ *
+ * Indicates a timeout.
+ */
+static void
+alrm(sig)
+ int sig;
+{
+ struct itimerval itv;
+ struct callout *freep, *list, *last;
+
+ MAINDEBUG((LOG_DEBUG, "Alarm"));
+
+ if (callout == NULL)
+ return;
+ /*
+ * Get the first scheduled timeout and any that were scheduled
+ * for the same time as a list, and remove them all from callout
+ * list.
+ */
+ list = last = callout;
+ while (last->c_next != NULL && last->c_next->c_time == 0)
+ last = last->c_next;
+ callout = last->c_next;
+ last->c_next = NULL;
+
+ /*
+ * Set a new itimer if there are more timeouts scheduled.
+ */
+ if (callout) {
+ itv.it_interval.tv_sec = itv.it_interval.tv_usec = 0;
+ itv.it_value.tv_usec = 0;
+ itv.it_value.tv_sec = callout->c_time;
+ MAINDEBUG((LOG_DEBUG, "Setting itimer for %d seconds in alrm.",
+ itv.it_value.tv_sec));
+ if (setitimer(ITIMER_REAL, &itv, NULL)) {
+ syslog(LOG_ERR, "setitimer(ITIMER_REAL): %m");
+ die(1);
+ }
+ if (gettimeofday(&schedtime, NULL)) {
+ syslog(LOG_ERR, "gettimeofday: %m");
+ die(1);
+ }
+ }
+
+ /*
+ * Now call all the timeout routines scheduled for this time.
+ */
+ while (list) {
+ (*list->c_func)(list->c_arg);
+ freep = list;
+ list = list->c_next;
+ (void) free((char *) freep);
+ }
+
+}
+
+
+/*
+ * chld - Catch SIGCHLD signal.
+ * Calls reap_kids to get status for any dead kids.
+ */
+static void
+chld(sig)
+ int sig;
+{
+ reap_kids();
+}
+
+
+/*
+ * io - Catch SIGIO signal.
+ *
+ * Indicates that incoming data is available.
+ */
+static void
+io(sig)
+ int sig;
+{
+ int len, i;
+ u_char *p;
+ u_short protocol;
+ fd_set fdset;
+ struct timeval notime;
+ int ready;
+
+ MAINDEBUG((LOG_DEBUG, "IO signal received"));
+ adjtimeout(); /* Adjust timeouts */
+
+ /* Yup, this is for real */
+ for (;;) { /* Read all available packets */
+ p = inpacket_buf; /* point to beginning of packet buffer */
+
+ len = read_packet(inpacket_buf);
+ if (len < 0)
+ return;
+
+ if (len == 0) {
+ MAINDEBUG((LOG_DEBUG, "End of file on fd!"));
+ lcp_lowerdown(0);
+ return;
+ }
+
+ if (debug /*&& (debugflags & DBG_INPACKET)*/)
+ log_packet(p, len, "rcvd ");
+
+ if (len < DLLHEADERLEN) {
+ MAINDEBUG((LOG_INFO, "io(): Received short packet."));
+ return;
+ }
+
+ p += 2; /* Skip address and control */
+ GETSHORT(protocol, p);
+ len -= DLLHEADERLEN;
+
+ /*
+ * Toss all non-LCP packets unless LCP is OPEN.
+ */
+ if (protocol != 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);
+ break;
+ }
+
+ if (i == sizeof (prottbl) / sizeof (struct protent)) {
+ syslog(LOG_WARNING, "input: Unknown protocol (%x) received!",
+ protocol);
+ lcp_sprotrej(0, p - DLLHEADERLEN, len + DLLHEADERLEN);
+ }
+ }
+}
+
+/*
+ * 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 %d!",
+ protocol);
+}
+
+
+/*
+ * incdebug - Catch SIGUSR1 signal.
+ *
+ * Increment debug flag.
+ */
+/*ARGSUSED*/
+static void
+incdebug(sig)
+ int sig;
+{
+ syslog(LOG_INFO, "Debug turned ON, Level %d", debug);
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ debug++;
+}
+
+
+/*
+ * nodebug - Catch SIGUSR2 signal.
+ *
+ * Turn off debugging.
+ */
+/*ARGSUSED*/
+static void
+nodebug(sig)
+ int sig;
+{
+ setlogmask(LOG_UPTO(LOG_WARNING));
+ debug = 0;
+}
+
+
+/*
+ * 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;
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGINT);
+ sigaddset(&mask, SIGHUP);
+ sigprocmask(SIG_BLOCK, &mask, &mask);
+
+ pid = fork();
+
+ if (pid < 0) {
+ syslog(LOG_ERR, "fork: %m");
+ die(1);
+ }
+
+ if (pid == 0) {
+ setreuid(getuid(), getuid());
+ setregid(getgid(), getgid());
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+ dup2(in, 0);
+ dup2(out, 1);
+ 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, "waiting for (dis)connection process: %m");
+ die(1);
+ }
+ sigprocmask(SIG_SETMASK, &mask, NULL);
+
+ 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;
+
+ pid = fork();
+ if (pid == -1) {
+ syslog(LOG_ERR, "can't fork to run %s: %m", prog);
+ return -1;
+ }
+ if (pid == 0) {
+ execv(prog, args);
+ 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, "waitpid: %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) __ARGS((void *, char *, ...));
+ void *arg;
+{
+ int i, n;
+ u_short proto;
+ u_char x;
+
+ if (len >= DLLHEADERLEN && p[0] == ALLSTATIONS && p[1] == UI) {
+ p += 2;
+ GETSHORT(proto, p);
+ len -= DLLHEADERLEN;
+ 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) __ARGS((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 0000000..480c860
--- /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 0000000..535b18d
--- /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 long 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 0000000..0656128
--- /dev/null
+++ b/usr.sbin/pppd/options.c
@@ -0,0 +1,1454 @@
+/*
+ * 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.10 1994/05/27 00:43:34 paulus Exp $";
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <limits.h>
+#define devname STDLIB_devname
+#include <stdlib.h>
+#undef devname
+#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 "ppp.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"
+
+#define FALSE 0
+#define TRUE 1
+
+#ifdef ultrix
+char *strdup __ARGS((char *));
+#endif
+
+#ifndef GIDSET_TYPE
+#define GIDSET_TYPE gid_t
+#endif
+
+/*
+ * Prototypes
+ */
+static int setdebug __ARGS((void));
+static int setkdebug __ARGS((char **));
+static int setpassive __ARGS((void));
+static int setsilent __ARGS((void));
+static int noopt __ARGS((void));
+static int setnovj __ARGS((void));
+static int setnovjccomp __ARGS((void));
+static int setvjslots __ARGS((char **));
+static int reqpap __ARGS((void));
+static int nopap __ARGS((void));
+static int setupapfile __ARGS((char **));
+static int nochap __ARGS((void));
+static int reqchap __ARGS((void));
+static int setspeed __ARGS((char *));
+static int noaccomp __ARGS((void));
+static int noasyncmap __ARGS((void));
+static int noipaddr __ARGS((void));
+static int nomagicnumber __ARGS((void));
+static int setasyncmap __ARGS((char **));
+static int setescape __ARGS((char **));
+static int setmru __ARGS((char **));
+static int setmtu __ARGS((char **));
+static int nomru __ARGS((void));
+static int nopcomp __ARGS((void));
+static int setconnector __ARGS((char **));
+static int setdisconnector __ARGS((char **));
+static int setdomain __ARGS((char **));
+static int setnetmask __ARGS((char **));
+static int setcrtscts __ARGS((void));
+static int setxonxoff __ARGS((void));
+static int setnodetach __ARGS((void));
+static int setmodem __ARGS((void));
+static int setlocal __ARGS((void));
+static int setlock __ARGS((void));
+static int setname __ARGS((char **));
+static int setuser __ARGS((char **));
+static int setremote __ARGS((char **));
+static int setauth __ARGS((void));
+static int readfile __ARGS((char **));
+static int setdefaultroute __ARGS((void));
+static int setproxyarp __ARGS((void));
+static int setpersist __ARGS((void));
+static int setdologin __ARGS((void));
+static int setusehostname __ARGS((void));
+static int setnoipdflt __ARGS((void));
+static int setlcptimeout __ARGS((char **));
+static int setlcpterm __ARGS((char **));
+static int setlcpconf __ARGS((char **));
+static int setlcpfails __ARGS((char **));
+static int setipcptimeout __ARGS((char **));
+static int setipcpterm __ARGS((char **));
+static int setipcpconf __ARGS((char **));
+static int setipcpfails __ARGS((char **));
+static int setpaptimeout __ARGS((char **));
+static int setpapreqs __ARGS((char **));
+static int setchaptimeout __ARGS((char **));
+static int setchapchal __ARGS((char **));
+static int setchapintv __ARGS((char **));
+static int setipcpaccl __ARGS((void));
+static int setipcpaccr __ARGS((void));
+static int setlcpechointv __ARGS((char **));
+static int setlcpechofails __ARGS((char **));
+
+static int number_option __ARGS((char *, long *, int));
+static int readable __ARGS((int fd));
+
+/*
+ * Option variables
+ */
+extern char *progname;
+extern int debug;
+extern int kdebugflag;
+extern int modem;
+extern int lockflag;
+extern int crtscts;
+extern int nodetach;
+extern char *connector;
+extern char *disconnector;
+extern int inspeed;
+extern char devname[];
+extern int default_device;
+extern u_long netmask;
+extern int detach;
+extern char user[];
+extern char passwd[];
+extern int auth_required;
+extern int proxyarp;
+extern int persist;
+extern int uselogin;
+extern u_long lcp_echo_interval;
+extern u_long lcp_echo_fails;
+extern char our_name[];
+extern char remote_name[];
+int usehostname;
+int disable_defaultip;
+
+/*
+ * 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 */
+ {"xonxoff", 0, setxonxoff}, /* set s/w flow control */
+ {"-crtscts", 0, setxonxoff}, /* another name for xonxoff */
+ {"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 */
+ {"proxyarp", 0, setproxyarp}, /* Add proxy ARP entry */
+ {"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 timeout for UPAP */
+ {"pap-max-authreq", 1, setpapreqs}, /* Set max #xmits for auth-reqs */
+ {"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 */
+ {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.
+ */
+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(devname, '/');
+ if (dev == NULL)
+ dev = devname;
+ 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 (").
+ * 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;
+
+ *newlinep = 0;
+ len = 0;
+ escape = 0;
+ quoted = 0;
+
+ /*
+ * First skip white-space and comments
+ */
+ while ((c = getc(f)) != EOF) {
+ if (c == '\\') {
+ /*
+ * \<newline> is ignored; \ followed by anything else
+ * starts a word.
+ */
+ if ((c = getc(f)) == '\n')
+ continue;
+ word[len++] = '\\';
+ escape = 1;
+ break;
+ }
+ if (c == '\n')
+ *newlinep = 1; /* next word starts a line */
+ else if (c == '#') {
+ /* comment - ignore until EOF or \n */
+ while ((c = getc(f)) != EOF && c != '\n')
+ ;
+ if (c == EOF)
+ break;
+ *newlinep = 1;
+ } else if (!isspace(c))
+ break;
+ }
+
+ /*
+ * End of file or error - fail
+ */
+ if (c == EOF) {
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+ return 0;
+ }
+
+ for (;;) {
+ /*
+ * Is this character escaped by \ ?
+ */
+ if (escape) {
+ if (c == '\n')
+ --len; /* ignore \<newline> */
+ else if (c == '"' || isspace(c) || c == '\\')
+ word[len-1] = c; /* put special char in word */
+ else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ }
+ escape = 0;
+ } else if (c == '"') {
+ quoted = !quoted;
+ } else if (!quoted && (isspace(c) || c == '#')) {
+ ungetc(c, f);
+ break;
+ } else {
+ if (len < MAXWORDLEN-1)
+ word[len] = c;
+ ++len;
+ if (c == '\\')
+ escape = 1;
+ }
+ if ((c = getc(f)) == EOF)
+ break;
+ }
+
+ if (ferror(f)) {
+ perror(filename);
+ die(1);
+ }
+
+ if (len >= MAXWORDLEN) {
+ word[MAXWORDLEN-1] = 0;
+ fprintf(stderr, "%s: warning: word in file %s too long (%.20s...)\n",
+ progname, filename, word);
+ } else
+ word[len] = 0;
+
+ return 1;
+}
+
+/*
+ * number_option - parse a numeric parameter for an option
+ */
+static int
+number_option(str, valp, base)
+ char *str;
+ long *valp;
+ int base;
+{
+ char *ptr;
+
+ *valp = strtol(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;
+{
+ long 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;
+{
+ long 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;
+{
+ long mtu;
+
+ if (!number_option(*argv, &mtu, 0))
+ return 0;
+ if (mtu < MINMRU || mtu > MAXMRU) {
+ fprintf(stderr, "mtu option value of %d 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;
+}
+
+
+/*
+ * 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;
+}
+
+
+/*
+ * 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;
+{
+ 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;
+{
+ long 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", 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(devname, cp, MAXPATHLEN);
+ devname[MAXPATHLEN-1] = 0;
+ default_device = FALSE;
+
+ return 1;
+}
+
+
+/*
+ * setipaddr - Set the IP address
+ */
+int
+setipaddr(arg)
+ char *arg;
+{
+ struct hostent *hp;
+ char *colon, *index();
+ u_long local, remote;
+ ipcp_options *wo = &ipcp_wantoptions[0];
+
+ /*
+ * IP address pair separated by ":".
+ */
+ if ((colon = index(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 = *(long *)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 = *(long *)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_long 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 = *(long *)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_long mask;
+
+ if ((mask = inet_addr(*argv)) == -1 || (netmask & ~mask) != 0) {
+ fprintf(stderr, "Invalid netmask %s\n", *argv);
+ return 0;
+ }
+
+ netmask = mask;
+ return (1);
+}
+
+/*
+ * Return user specified netmask. A value of zero means no netmask has
+ * been set.
+ */
+/* ARGSUSED */
+u_long
+GetMask(addr)
+ u_long addr;
+{
+ return(netmask);
+}
+
+
+static int
+setcrtscts()
+{
+ crtscts = 1;
+ return (1);
+}
+
+static int
+setxonxoff()
+{
+ 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()
+{
+ ipcp_wantoptions[0].default_route = 1;
+ return 1;
+}
+
+static int
+setproxyarp()
+{
+ ipcp_wantoptions[0].proxy_arp = 1;
+ 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 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);
+}
diff --git a/usr.sbin/pppd/patchlevel.h b/usr.sbin/pppd/patchlevel.h
new file mode 100644
index 0000000..ad290b0
--- /dev/null
+++ b/usr.sbin/pppd/patchlevel.h
@@ -0,0 +1,5 @@
+/* $Id: patchlevel.h,v 1.10 1994/06/09 01:51:10 paulus Exp $ */
+#define PATCHLEVEL 2
+
+#define VERSION "2.1"
+#define DATE "9 June 94"
diff --git a/usr.sbin/pppd/pathnames.h b/usr.sbin/pppd/pathnames.h
new file mode 100644
index 0000000..d8e91dc
--- /dev/null
+++ b/usr.sbin/pppd/pathnames.h
@@ -0,0 +1,19 @@
+/*
+ * define path names
+ *
+ * $Id: pathnames.h,v 1.4 1994/05/18 06:34:46 paulus Exp $
+ */
+
+#if defined(STREAMS) || defined(ultrix)
+#define _PATH_PIDFILE "/etc/ppp"
+#else
+#define _PATH_PIDFILE "/var/run"
+#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_USEROPT ".ppprc"
diff --git a/usr.sbin/pppd/ppp.h b/usr.sbin/pppd/ppp.h
new file mode 100644
index 0000000..3d8f870
--- /dev/null
+++ b/usr.sbin/pppd/ppp.h
@@ -0,0 +1,41 @@
+/*
+ * ppp.h - PPP 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: ppp.h,v 1.1 1993/11/11 03:54:25 paulus Exp $
+ */
+
+#ifndef __PPP_H__
+#define __PPP_H__
+
+#define NPPP 1 /* One PPP interface supported (per process) */
+
+/*
+ * Data Link Layer header = Address, Control, Protocol.
+ */
+#define ALLSTATIONS 0xff /* All-Stations Address */
+#define UI 0x03 /* Unnumbered Information */
+#define LCP 0xc021 /* Link Control Protocol */
+#define IPCP 0x8021 /* IP Control Protocol */
+#define UPAP 0xc023 /* User/Password Authentication Protocol */
+#define CHAP 0xc223 /* Crytpographic Handshake Protocol */
+#define LQR 0xc025 /* Link Quality Report protocol */
+#define IP_VJ_COMP 0x002d /* VJ TCP compressed IP packet */
+#define DLLHEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+#define MTU 1500 /* Default MTU */
+
+#endif /* __PPP_H__ */
diff --git a/usr.sbin/pppd/pppd.8 b/usr.sbin/pppd/pppd.8
new file mode 100644
index 0000000..3395631
--- /dev/null
+++ b/usr.sbin/pppd/pppd.8
@@ -0,0 +1,701 @@
+.\" manual page [] for pppd 2.0
+.\" $Id: pppd.8,v 1.7 1994/06/09 01:50:48 paulus 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 options
+] [
+.I tty_name
+] [
+.I speed
+]
+.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,
+.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>. 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 will 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" 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.
+.TP
+.B xonxoff
+Use software flow control (i.e. XON/XOFF) to control the flow of data on
+the serial port. This option is not implemented on BSD or Ultrix systems
+at present.
+.TP
+.B -crtscts
+A synonym for \fBxonxoff\fR.
+.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 use a UUCP-style lock on 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 netmask \fI<n>
+Set the interface netmask to <n>, a 32 bit netmask in "decimal dot" notation
+(e.g. 255.255.255.0).
+.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
+old 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 -all
+Don't request or allow negotiation of any options for LCP and IPCP (use
+default values).
+.TP
+.B -ac
+Disable Address/Control compression negotiation (use default, i.e.
+address/control field disabled).
+.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 -d
+Increase debugging level (same as the \fBdebug\fR option).
+.TP
+.B -detach
+Don't fork to become a background process (otherwise
+.I pppd
+will do so if a serial device is specified).
+.TP
+.B -ip
+Disable IP address negotiation (with this option, the remote IP
+address must be specified with an option on the command line or in an
+options file).
+.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 (use default, i.e. 1500).
+.TP
+.B -p
+Same as the
+.B passive
+option.
+.TP
+.B -pc
+Disable protocol field compression negotiation (use default, i.e.
+protocol field compression disabled).
+.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 +pap
+Require the peer to authenticate itself using PAP.
+.TP
+.B -pap
+Don't agree to authenticate using PAP.
+.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 -vj
+Disable negotiation of Van Jacobson style IP header compression (use
+default, i.e. no compression).
+.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)). (If \fIpppd\fR is compiled with
+extra debugging enabled, it will log messages using facility
+\fIlocal2\fR instead of \fIdaemon\fR).
+.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 modem
+Use the modem control lines. On Ultrix, this option implies hardware
+flow control, as for the \fBcrtscts\fR option. (This option is not fully
+implemented.)
+.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 local
+Don't use the modem control lines.
+.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 name \fI<n>
+Set the name of the local system for authentication purposes to <n>.
+.TP
+.B user \fI<u>
+Set the user name to use for authenticating this machine with the peer
+using PAP to <u>.
+.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 remotename \fI<n>
+Set the assumed name of the remote system for authentication purposes
+to <n>.
+.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 login
+Use the system password database for authenticating the peer using
+PAP.
+.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 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-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-restart \fI<n>
+Set the LCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B lcp-max-terminate \fI<n>
+Set the maximum number of LCP terminate-request transmissions to <n>
+(default 3).
+.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 ipcp-restart \fI<n>
+Set the IPCP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B ipcp-max-terminate \fI<n>
+Set the maximum number of IPCP terminate-request transmissions to <n>
+(default 3).
+.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 pap-restart \fI<n>
+Set the PAP restart interval (retransmission timeout) to <n> seconds
+(default 3).
+.TP
+.B pap-max-authreq \fI<n>
+Set the maximum number of PAP authenticate-request 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 chap-max-challenge \fI<n>
+Set the maximum number of CHAP challenge transmissions to <n> (default
+10).
+.TP
+.B chap-interval \fI<n>
+If this option is given,
+.I pppd
+will rechallenge the peer every <n> seconds.
+.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.
+.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, server, 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 \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.
+.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, \fIpppd\fR uses facility
+LOG_LOCAL2 instead of LOG_DAEMON, and the \fBdebug\fR option
+causes additional debugging messages to be logged.
+.LP
+Debugging can also be enabled by sending a
+SIGUSR1 to the
+.I pppd
+process.
+Debugging may be disabled by sending a SIGUSR2 to the
+.I pppd
+process.
+.SH FILES
+.TP
+.B /var/run/ppp\fIn\fB.pid \fR(BSD), \fB/etc/ppp/ppp\fIn\fB.pid \fR(SunOS)
+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 \fIinterface-name tty-device speed
+local-IP-address remote-IP-address\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 \fIpppd\fR to terminate the link (by closing LCP),
+restore the serial device settings, and exit.
+.TP
+.B SIGHUP
+Indicates that the physical layer has been disconnected. \fIpppd\fR
+will attempt to restore the serial device settings (this may produce
+error messages on Suns), and then exit.
+.SH BUGS
+The use of the modem control lines and the effects of the \fBmodem\fR
+and \fBlocal\fR options are not well defined.
+.SH AUTHORS
+Drew Perkins,
+Brad Clements,
+Karl Fox,
+Greg Christy,
+Brad Parker (brad@fcr.com),
+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 0000000..e38687d
--- /dev/null
+++ b/usr.sbin/pppd/pppd.h
@@ -0,0 +1,215 @@
+/*
+ * 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.3 1994/05/26 06:43:42 paulus Exp $
+ */
+
+/*
+ * TODO:
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+#include "args.h"
+
+#include <sys/param.h> /* for MAXPATHLEN and BSD4_4, if defined */
+
+#define NPPP 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 debug; /* Debug flag */
+extern int ifunit; /* Interface unit number */
+extern char ifname[]; /* Interface name */
+extern int fd; /* Device file descriptor */
+extern int s; /* socket descriptor */
+extern char hostname[]; /* hostname */
+extern u_char outpacket_buf[]; /* buffer for outgoing packets */
+extern int phase; /* See values below */
+
+/*
+ * 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 __ARGS((void)); /* Cleanup and exit */
+void timeout __ARGS((void (*)(), caddr_t, int));
+ /* Look-alike of kernel's timeout() */
+void untimeout __ARGS((void (*)(), caddr_t));
+ /* Look-alike of kernel's untimeout() */
+void output __ARGS((int, u_char *, int));
+ /* Output a PPP packet */
+void demuxprotrej __ARGS((int, int));
+ /* Demultiplex a Protocol-Reject */
+int check_passwd __ARGS((int, char *, int, char *, int, char **, int *));
+ /* Check peer-supplied username/password */
+int get_secret __ARGS((int, char *, char *, char *, int *, int));
+ /* get "secret" for chap */
+u_long GetMask __ARGS((u_long)); /* get netmask for address */
+
+
+/*
+ * 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))
+
+/*
+ * 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(ALLSTATIONS, p); \
+ PUTCHAR(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/sys-bsd.c b/usr.sbin/pppd/sys-bsd.c
new file mode 100644
index 0000000..65c0b77
--- /dev/null
+++ b/usr.sbin/pppd/sys-bsd.c
@@ -0,0 +1,743 @@
+/*
+ * 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.7 1994/05/30 06:10:07 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+#include <net/if.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"
+#include "ppp.h"
+
+static int initdisc = -1; /* Initial TTY discipline */
+extern int kdebugflag;
+static int rtm_seq;
+
+/*
+ * 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");
+ }
+}
+
+
+/*
+ * 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);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
+ if (errno == EWOULDBLOCK) {
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+ 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_long 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(s, 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_long 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();
+ }
+}
+
+/*
+ * 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.
+ */
+int
+sifup(u)
+ int u;
+{
+ struct ifreq ifr;
+ u_int x;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ 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;
+
+ rv = 1;
+ 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(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ rv = 0;
+ } else {
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, 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_long 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(s, 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_long 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(s, 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_long g;
+{
+ return dodefaultroute(g, 's');
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+ int u;
+ u_long g;
+{
+ return dodefaultroute(g, 'c');
+}
+
+/*
+ * dodefaultroute - talk to a routing socket to add/delete a default route.
+ */
+int
+dodefaultroute(g, cmd)
+ u_long 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_long 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_long 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_long 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(s, 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_long 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(s, 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_long ipaddr;
+ struct sockaddr_dl *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long 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(s, 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; ) {
+ 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(s, 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(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+ }
+
+ 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;
+}
+
+
+/*
+ * 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;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}
diff --git a/usr.sbin/pppd/sys-linux.c b/usr.sbin/pppd/sys-linux.c
new file mode 100644
index 0000000..306ae4a
--- /dev/null
+++ b/usr.sbin/pppd/sys-linux.c
@@ -0,0 +1,830 @@
+/*
+ * sys-linux.c - System-dependent procedures for setting up
+ * PPP interfaces on Linux systems
+ *
+ * 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.
+ */
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <syslog.h>
+#include <string.h>
+#include <time.h>
+#include <memory.h>
+#include <utmp.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <mntent.h>
+
+#include <net/if.h>
+#include <linux/ppp.h>
+#include <linux/route.h>
+#include <linux/if_ether.h>
+#include <netinet/in.h>
+#include <signal.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+static int initdisc = -1; /* Initial TTY discipline */
+static int prev_kdebugflag = 0;
+extern int kdebugflag;
+extern u_long netmask;
+
+#define MAX_IFS 32
+
+/* prototypes */
+void die __ARGS((int));
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+
+#define SET_SA_FAMILY(addr, family) \
+ memset ((char *) &(addr), '\0', sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * set_kdebugflag - Define the debugging level for the kernel
+ */
+
+int set_kdebugflag (int requested_level)
+{
+ if (ioctl(fd, PPPIOCGDEBUG, &prev_kdebugflag) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGDEBUG): %m");
+ return (0);
+ }
+
+ if (prev_kdebugflag != requested_level) {
+ if (ioctl(fd, PPPIOCSDEBUG, &requested_level) < 0) {
+ syslog (LOG_ERR, "ioctl(PPPIOCSDEBUG): %m");
+ return (0);
+ }
+ syslog(LOG_INFO, "set kernel debugging level to %d", requested_level);
+ }
+ return (1);
+}
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+
+void establish_ppp (void)
+{
+ int pppdisc = N_PPP;
+ int sig = SIGIO;
+
+ if (ioctl(fd, PPPIOCSINPSIG, &sig) == -1) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSINPSIG): %m");
+ die(1);
+ }
+
+ if (ioctl(fd, TIOCEXCL, 0) < 0) {
+ syslog (LOG_WARNING, "ioctl(TIOCEXCL): %m");
+ }
+
+ 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);
+ }
+
+ if (ioctl(fd, PPPIOCGUNIT, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m");
+ die (1);
+ }
+
+ set_kdebugflag (kdebugflag);
+}
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+
+void disestablish_ppp(void)
+{
+ int x;
+ char *s;
+
+ if (initdisc >= 0) {
+ set_kdebugflag (prev_kdebugflag);
+ /*
+ * 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");
+
+ if (ioctl(fd, TIOCNXCL, 0) < 0)
+ syslog (LOG_WARNING, "ioctl(TIOCNXCL): %m");
+
+ initdisc = -1;
+ }
+}
+
+/*
+ * output - Output PPP packet.
+ */
+
+void output (int unit, unsigned 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);
+ }
+}
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+
+int read_packet (unsigned char *buf)
+{
+ int len;
+
+ len = read(fd, buf, MTU + DLLHEADERLEN);
+ if (len < 0) {
+ if (errno == EWOULDBLOCK) {
+#if 0
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+#endif
+ 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 (int unit,int mtu,u_long asyncmap,int pcomp,int accomp)
+{
+ u_int x;
+ struct ifreq ifr;
+
+ MAINDEBUG ((LOG_DEBUG, "send_config: mtu = %d\n", mtu));
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ MAINDEBUG ((LOG_DEBUG, "send_config: asyncmap = %lx\n", asyncmap));
+ 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;
+
+ MAINDEBUG ((LOG_DEBUG, "send_config: flags = %x\n", x));
+ 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;
+{
+ MAINDEBUG ((LOG_DEBUG, "set_xaccm: %08lx %08lx %08lx %08lx\n",
+ accm[0], accm[1], accm[2], accm[3]));
+ 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 (int unit,int mru,u_long asyncmap,int pcomp,int accomp)
+{
+ u_int x;
+
+ MAINDEBUG ((LOG_DEBUG, "recv_config: mru = %d\n", mru));
+ if (ioctl(fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+ syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %m");
+
+ MAINDEBUG ((LOG_DEBUG, "recv_config: asyncmap = %lx\n", asyncmap));
+ if (ioctl(fd, PPPIOCRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCRASYNCMAP): %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;
+ MAINDEBUG ((LOG_DEBUG, "recv_config: flags = %x\n", x));
+ if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %m");
+ quit();
+ }
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+
+int sifvjcomp (int u, int vjcomp, int cidcomp, int 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 (vjcomp) {
+ 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.
+ */
+
+int sifup (int u)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+
+int sifdown (int u)
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+
+int sifaddr (int unit, int our_adr, int his_adr, int net_mask)
+{
+ struct ifreq ifr;
+ struct rtentry rt;
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr;
+ if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (errno != EEXIST)
+ syslog (LOG_ERR, "ioctl(SIOCAIFADDR): %m");
+ else
+ syslog (LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr;
+ if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ syslog (LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
+ return (0);
+ }
+/*
+ * Set the netmask
+ */
+ if (net_mask != 0) {
+ ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask;
+ if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ syslog (LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname; /* MJC */
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m");
+ return (0);
+ }
+ return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+
+int cifaddr (int unit, int our_adr, int his_adr)
+{
+ struct rtentry rt;
+/*
+ * Delete the route through the device
+ */
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname; /* MJC */
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (ioctl(s, SIOCDELRT, &rt) < 0) {
+ syslog (LOG_ERR, "ioctl(SIOCDELRT) device route: %m");
+ return (0);
+ }
+ return 1;
+}
+
+/*
+ * path_to_route - determine the path to the proc file system data
+ */
+
+FILE *route_fd = (FILE *) 0;
+static char route_buffer [100];
+
+static char *path_to_route (void);
+static int open_route_table (void);
+static void close_route_table (void);
+static int read_route_table (struct rtentry *rt);
+static int defaultroute_exists (void);
+
+/*
+ * path_to_route - find the path to the route tables in the proc file system
+ */
+
+static char *path_to_route (void)
+{
+ struct mntent *mntent;
+ FILE *fp;
+
+ fp = fopen (MOUNTED, "r");
+ if (fp != 0) {
+ while ((mntent = getmntent (fp)) != 0) {
+ if (strcmp (mntent->mnt_type, MNTTYPE_IGNORE) == 0)
+ continue;
+
+ if (strcmp (mntent->mnt_type, "proc") == 0) {
+ strncpy (route_buffer, mntent->mnt_dir,
+ sizeof (route_buffer)-10);
+ route_buffer [sizeof (route_buffer)-10] = '\0';
+ strcat (route_buffer, "/net/route");
+
+ fclose (fp);
+ return (route_buffer);
+ }
+ }
+ fclose (fp);
+ }
+ syslog (LOG_ERR, "proc file system not mounted");
+ return 0;
+}
+
+/*
+ * open_route_table - open the interface to the route table
+ */
+
+static int open_route_table (void)
+{
+ char *path;
+
+ if (route_fd != (FILE *) 0)
+ close_route_table();
+
+ path = path_to_route();
+ if (path == NULL)
+ return 0;
+
+ route_fd = fopen (path, "r");
+ if (route_fd == (FILE *) 0) {
+ syslog (LOG_ERR, "can not open %s: %m", path);
+ return 0;
+ }
+
+ /* read and discard the header line. */
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0) {
+ close_route_table();
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * close_route_table - close the interface to the route table
+ */
+
+static void close_route_table (void)
+{
+ if (route_fd != (FILE *) 0) {
+ fclose (route_fd);
+ route_fd = (FILE *) 0;
+ }
+}
+
+/*
+ * read_route_table - read the next entry from the route table
+ */
+
+static int read_route_table (struct rtentry *rt)
+{
+ static char delims[] = " \t\n";
+ char *dev_ptr, *ptr, *dst_ptr, *gw_ptr, *flag_ptr;
+
+ if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
+ return 0;
+
+ memset (rt, '\0', sizeof (struct rtentry));
+
+ dev_ptr = strtok (route_buffer, delims); /* interface name */
+ dst_ptr = strtok (NULL, delims); /* destination address */
+ gw_ptr = strtok (NULL, delims); /* gateway */
+ flag_ptr = strtok (NULL, delims); /* flags */
+#if 0
+ ptr = strtok (NULL, delims); /* reference count */
+ ptr = strtok (NULL, delims); /* useage count */
+ ptr = strtok (NULL, delims); /* metric */
+ ptr = strtok (NULL, delims); /* mask */
+#endif
+
+ ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr =
+ strtoul (dst_ptr, NULL, 16);
+
+ ((struct sockaddr_in *) &rt->rt_gateway)->sin_addr.s_addr =
+ strtoul (gw_ptr, NULL, 16);
+
+ rt->rt_flags = (short) strtoul (flag_ptr, NULL, 16);
+ rt->rt_dev = dev_ptr;
+
+ return 1;
+}
+
+/*
+ * defaultroute_exists - determine if there is a default route
+ */
+
+static int defaultroute_exists (void)
+{
+ struct rtentry rt;
+ int result = 0;
+
+ if (!open_route_table())
+ return 0;
+
+ while (read_route_table(&rt) != 0) {
+ if (rt.rt_flags & RTF_UP == 0)
+ continue;
+
+ if (((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr == 0L) {
+ syslog (LOG_ERR,
+ "ppp not replacing existing default route to %s[%s]",
+ rt.rt_dev,
+ inet_ntoa (((struct sockaddr_in *) &rt.rt_gateway)->
+ sin_addr.s_addr));
+ result = 1;
+ break;
+ }
+ }
+ close_route_table();
+ return result;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+
+int sifdefaultroute (int unit, int gateway)
+{
+ struct rtentry rt;
+
+ if (defaultroute_exists())
+ return 0;
+
+ memset (&rt, '\0', sizeof (rt));
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog (LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+
+int cifdefaultroute (int unit, int gateway)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = gateway;
+
+ rt.rt_flags = RTF_UP | RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0) {
+ syslog (LOG_ERR, "default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+
+int sifproxyarp (int unit, u_long his_adr)
+{
+ struct arpreq arpreq;
+
+ memset (&arpreq, '\0', sizeof(arpreq));
+/*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(his_adr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
+ arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+
+ if (ioctl(s, 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 (int unit, u_long his_adr)
+{
+ struct arpreq arpreq;
+
+ memset (&arpreq, '\0', sizeof(arpreq));
+ SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+
+ ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = his_adr;
+ if (ioctl(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+
+int get_ether_addr (u_long ipaddr, struct sockaddr *hwaddr)
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ int i;
+ u_long 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(s, SIOCGIFCONF, &ifc) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+ return 0;
+ }
+ MAINDEBUG ((LOG_DEBUG, "proxy arp: scanning %d interfaces for IP %s",
+ ifc.ifc_len / sizeof(struct ifreq), ip_ntoa(ipaddr)));
+/*
+ * Scan through looking for an interface with an Internet
+ * address on the same subnet as `ipaddr'.
+ */
+ ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
+ for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
+ 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));
+ MAINDEBUG ((LOG_DEBUG, "proxy arp: examining interface %s",
+ ifreq.ifr_name));
+/*
+ * Check that the interface is up, and not point-to-point
+ * or loopback.
+ */
+ if (ioctl(s, 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(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+ MAINDEBUG ((LOG_DEBUG, "proxy arp: interface addr %s mask %lx",
+ ip_ntoa(ina), ntohl(mask)));
+ if (((ipaddr ^ ina) & mask) != 0)
+ continue;
+ break;
+ }
+ }
+
+ if (ifr >= ifend)
+ return 0;
+
+ syslog(LOG_INFO, "found interface %s for proxy arp", ifreq.ifr_name);
+/*
+ * Now get the hardware address.
+ */
+ if (ioctl (s, SIOCGIFHWADDR, &ifreq) < 0) {
+ syslog(LOG_ERR, "SIOCGIFHWADDR(%s): %m", ifreq.ifr_name);
+ return 0;
+ }
+
+ hwaddr->sa_family = ARPHRD_ETHER;
+#ifndef old_ifr_hwaddr
+ memcpy (&hwaddr->sa_data, &ifreq.ifr_hwaddr, ETH_ALEN);
+#else
+ memcpy (&hwaddr->sa_data, &ifreq.ifr_hwaddr.sa_data, ETH_ALEN);
+#endif
+
+ MAINDEBUG ((LOG_DEBUG,
+ "proxy arp: found hwaddr %02x:%02x:%02x:%02x:%02x:%02x",
+ (int) ((unsigned char *) &hwaddr->sa_data)[0],
+ (int) ((unsigned char *) &hwaddr->sa_data)[1],
+ (int) ((unsigned char *) &hwaddr->sa_data)[2],
+ (int) ((unsigned char *) &hwaddr->sa_data)[3],
+ (int) ((unsigned char *) &hwaddr->sa_data)[4],
+ (int) ((unsigned char *) &hwaddr->sa_data)[5]));
+ return 1;
+}
+
+/*
+ * 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(void)
+{
+ int s, ok;
+ struct ifreq ifr;
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}
+
+int
+logwtmp(line, name, host)
+ char *line, *name, *host;
+{
+ struct utmp ut;
+
+ memset (&ut, 0, sizeof (ut));
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time(&ut.ut_time);
+
+ pututline (&ut); /* Write the line to the proper place */
+ endutent(); /* Indicate operation is complete */
+}
diff --git a/usr.sbin/pppd/sys-str.c b/usr.sbin/pppd/sys-str.c
new file mode 100644
index 0000000..c197d4b
--- /dev/null
+++ b/usr.sbin/pppd/sys-str.c
@@ -0,0 +1,730 @@
+/*
+ * sys-str.c - System-dependent procedures for setting up
+ * PPP interfaces on systems which use the STREAMS ppp interface.
+ *
+ * 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.
+ */
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <utmp.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+#include <net/ppp_str.h>
+
+#ifndef ifr_mtu
+#define ifr_mtu ifr_metric
+#endif
+
+#define MAXMODULES 10 /* max number of module names to save */
+static struct modlist {
+ char modname[FMNAMESZ+1];
+} str_modules[MAXMODULES];
+static int str_module_count = 0;
+static int pushed_ppp;
+
+extern int hungup; /* has the physical layer been disconnected? */
+extern int kdebugflag;
+
+#define PAI_FLAGS_B7_0 0x100
+#define PAI_FLAGS_B7_1 0x200
+#define PAI_FLAGS_PAR_EVEN 0x400
+#define PAI_FLAGS_PAR_ODD 0x800
+#define PAI_FLAGS_HIBITS 0xF00
+
+/*
+ * ppp_available - check if this kernel supports PPP.
+ */
+int
+ppp_available()
+{
+ int fd, ret;
+
+ fd = open("/dev/tty", O_RDONLY, 0);
+ if (fd < 0)
+ return 1; /* can't find out - assume we have ppp */
+ ret = ioctl(fd, I_FIND, "pppasync") >= 0;
+ close(fd);
+ return ret;
+}
+
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp()
+{
+ /* go through and save the name of all the modules, then pop em */
+ for (;;) {
+ if (ioctl(fd, I_LOOK, str_modules[str_module_count].modname) < 0 ||
+ ioctl(fd, I_POP, 0) < 0)
+ break;
+ MAINDEBUG((LOG_DEBUG, "popped stream module : %s",
+ str_modules[str_module_count].modname));
+ str_module_count++;
+ }
+
+ /* now push the async/fcs module */
+ if (ioctl(fd, I_PUSH, "pppasync") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_async): %m");
+ die(1);
+ }
+ /* finally, push the ppp_if module that actually handles the */
+ /* network interface */
+ if (ioctl(fd, I_PUSH, "pppif") < 0) {
+ syslog(LOG_ERR, "ioctl(I_PUSH, ppp_if): %m");
+ die(1);
+ }
+ pushed_ppp = 1;
+ if (ioctl(fd, I_SETSIG, S_INPUT) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SETSIG, S_INPUT): %m");
+ die(1);
+ }
+ /* read mode, message non-discard mode */
+ if (ioctl(fd, I_SRDOPT, RMSGN) < 0) {
+ syslog(LOG_ERR, "ioctl(I_SRDOPT, RMSGN): %m");
+ die(1);
+ }
+ /* Flush any waiting messages, or we'll never get SIGPOLL */
+ if (ioctl(fd, I_FLUSH, FLUSHRW) < 0) {
+ syslog(LOG_ERR, "ioctl(I_FLUSH, FLUSHRW): %m");
+ die(1);
+ }
+ /*
+ * Find out which interface we were given.
+ * (ppp_if handles this ioctl)
+ */
+ if (ioctl(fd, SIOCGETU, &ifunit) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCGETU): %m");
+ die(1);
+ }
+
+ /* Set debug flags in driver */
+ if (ioctl(fd, SIOCSIFDEBUG, &kdebugflag) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDEBUG): %m");
+ }
+}
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * It attempts to reconstruct the stream with the previously popped
+ * modules. This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp()
+{
+ int flags;
+ char *s;
+
+ if (hungup) {
+ /* we can't push or pop modules after the stream has hung up */
+ str_module_count = 0;
+ return;
+ }
+
+ if (pushed_ppp) {
+ /*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+ if (ioctl(fd, SIOCGIFDEBUG, (caddr_t) &flags) == 0) {
+ s = NULL;
+ switch (~flags & PAI_FLAGS_HIBITS) {
+ case PAI_FLAGS_B7_0:
+ s = "bit 7 set to 1";
+ break;
+ case PAI_FLAGS_B7_1:
+ s = "bit 7 set to 0";
+ break;
+ case PAI_FLAGS_PAR_EVEN:
+ s = "odd parity";
+ break;
+ case PAI_FLAGS_PAR_ODD:
+ 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);
+ }
+ }
+ }
+
+ while (ioctl(fd, I_POP, 0) == 0) /* pop any we pushed */
+ ;
+ pushed_ppp = 0;
+
+ for (; str_module_count > 0; str_module_count--) {
+ if (ioctl(fd, I_PUSH, str_modules[str_module_count-1].modname)) {
+ syslog(LOG_WARNING, "str_restore: couldn't push module %s: %m",
+ str_modules[str_module_count-1].modname);
+ } else {
+ MAINDEBUG((LOG_INFO, "str_restore: pushed module %s",
+ str_modules[str_module_count-1].modname));
+ }
+ }
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+ int unit;
+ u_char *p;
+ int len;
+{
+ struct strbuf str;
+
+ if (unit != 0)
+ MAINDEBUG((LOG_WARNING, "output: unit != 0!"));
+ if (debug)
+ log_packet(p, len, "sent ");
+
+ str.len = len;
+ str.buf = (caddr_t) p;
+ if(putmsg(fd, NULL, &str, 0) < 0) {
+ syslog(LOG_ERR, "putmsg: %m");
+ die(1);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ struct strbuf str;
+ int len, i;
+
+ str.maxlen = MTU+DLLHEADERLEN;
+ str.buf = (caddr_t) buf;
+ i = 0;
+ len = getmsg(fd, NULL, &str, &i);
+ if (len < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return -1;
+ }
+ syslog(LOG_ERR, "getmsg(fd) %m");
+ die(1);
+ }
+ if (len)
+ MAINDEBUG((LOG_DEBUG, "getmsg returned 0x%x",len));
+
+ if (str.len < 0) {
+ MAINDEBUG((LOG_DEBUG, "getmsg short return length %d", str.len));
+ return -1;
+ }
+
+ return str.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_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ioctl(s, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %m");
+ quit();
+ }
+
+ if(ioctl(fd, SIOCSIFASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFASYNCMAP): %m");
+ quit();
+ }
+
+ c = (pcomp? 1: 0);
+ if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
+ quit();
+ }
+
+ c = (accomp? 1: 0);
+ if(ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %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, SIOCSIFXASYNCMAP, 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_long asyncmap;
+ int pcomp, accomp;
+{
+ char c;
+
+ if (ioctl(fd, SIOCSIFMRU, &mru) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFMRU): %m");
+ }
+
+ if (ioctl(fd, SIOCSIFRASYNCMAP, (caddr_t) &asyncmap) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFRASYNCMAP): %m");
+ }
+
+ c = 2 + (pcomp? 1: 0);
+ if(ioctl(fd, SIOCSIFCOMPPROT, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPPROT): %m");
+ }
+
+ c = 2 + (accomp? 1: 0);
+ if (ioctl(fd, SIOCSIFCOMPAC, &c) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFCOMPAC): %m");
+ }
+}
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp, maxcid)
+ int u, vjcomp, cidcomp, maxcid;
+{
+ char x;
+
+ x = (vjcomp? 1: 0) + (cidcomp? 0: 2) + (maxcid << 4);
+ if (ioctl(fd, SIOCSIFVJCOMP, (caddr_t) &x) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFVJCOMP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifup - Config the interface up.
+ */
+int
+sifup(u)
+ int u;
+{
+ struct ifreq ifr;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdown - Config the interface down.
+ */
+int
+sifdown(u)
+ int u;
+{
+ struct ifreq ifr;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * SET_SA_FAMILY - initialize a struct sockaddr, setting the sa_family field.
+ */
+#define SET_SA_FAMILY(addr, family) \
+ BZERO((char *) &(addr), sizeof(addr)); \
+ addr.sa_family = (family);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+ int u;
+ u_long o, h, m;
+{
+ int ret;
+ struct ifreq ifr;
+
+ ret = 1;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
+ if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
+ ret = 0;
+ }
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
+ if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
+ ret = 0;
+ }
+ if (m != 0) {
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
+ if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+ int u;
+ u_long o, h;
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
+ rt.rt_flags = RTF_HOST;
+ if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+ int u;
+ u_long g;
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+ int u;
+ u_long g;
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_WARNING, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ 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(s, 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_long 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(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr. Code borrowed from myetheraddr.c
+ * in the cslip-2.6 distribution, which is subject to the following
+ * copyright notice (which also applies to logwtmp below):
+ *
+ * Copyright (c) 1990, 1992 The Regents 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.
+ */
+
+#include <fcntl.h>
+#include <nlist.h>
+#include <kvm.h>
+#include <arpa/inet.h>
+
+/* XXX SunOS 4.1 defines this and 3.5 doesn't... */
+#ifdef _nlist_h
+#define SUNOS4
+#endif
+
+#ifdef SUNOS4
+#include <netinet/in_var.h>
+#endif
+#include <netinet/if_ether.h>
+
+/* Cast a struct sockaddr to a structaddr_in */
+#define SATOSIN(sa) ((struct sockaddr_in *)(sa))
+
+/* Determine if "bits" is set in "flag" */
+#define ALLSET(flag, bits) (((flag) & (bits)) == (bits))
+
+static struct nlist nl[] = {
+#define N_IFNET 0
+ { "_ifnet" },
+ { 0 }
+};
+
+static void kread();
+
+int
+get_ether_addr(ipaddr, hwaddr)
+ u_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ register kvm_t *kd;
+ register struct ifnet *ifp;
+ register struct arpcom *ac;
+ struct arpcom arpcom;
+ struct in_addr *inp;
+#ifdef SUNOS4
+ register struct ifaddr *ifa;
+ register struct in_ifaddr *in;
+ union {
+ struct ifaddr ifa;
+ struct in_ifaddr in;
+ } ifaddr;
+#endif
+ u_long addr, mask;
+
+ /* Open kernel memory for reading */
+ kd = kvm_open(0, 0, 0, O_RDONLY, NULL);
+ if (kd == 0) {
+ syslog(LOG_ERR, "kvm_open: %m");
+ return 0;
+ }
+
+ /* Fetch namelist */
+ if (kvm_nlist(kd, nl) != 0) {
+ syslog(LOG_ERR, "kvm_nlist failed");
+ return 0;
+ }
+
+ ac = &arpcom;
+ ifp = &arpcom.ac_if;
+#ifdef SUNOS4
+ ifa = &ifaddr.ifa;
+ in = &ifaddr.in;
+#endif
+
+ if (kvm_read(kd, nl[N_IFNET].n_value, (char *)&addr, sizeof(addr))
+ != sizeof(addr)) {
+ syslog(LOG_ERR, "error reading ifnet addr");
+ return 0;
+ }
+ for ( ; addr; addr = (u_long)ifp->if_next) {
+ if (kvm_read(kd, addr, (char *)ac, sizeof(*ac)) != sizeof(*ac)) {
+ syslog(LOG_ERR, "error reading ifnet");
+ return 0;
+ }
+
+ /* Only look at configured, broadcast interfaces */
+ if (!ALLSET(ifp->if_flags, IFF_UP | IFF_BROADCAST))
+ continue;
+#ifdef SUNOS4
+ /* This probably can't happen... */
+ if (ifp->if_addrlist == 0)
+ continue;
+#endif
+
+ /* Get interface ip address */
+#ifdef SUNOS4
+ if (kvm_read(kd, (u_long)ifp->if_addrlist, (char *)&ifaddr,
+ sizeof(ifaddr)) != sizeof(ifaddr)) {
+ syslog(LOG_ERR, "error reading ifaddr");
+ return 0;
+ }
+ inp = &SATOSIN(&ifa->ifa_addr)->sin_addr;
+#else
+ inp = &SATOSIN(&ifp->if_addr)->sin_addr;
+#endif
+
+ /* Check if this interface on the right subnet */
+#ifdef SUNOS4
+ mask = in->ia_subnetmask;
+#else
+ mask = ifp->if_subnetmask;
+#endif
+ if ((ipaddr & mask) != (inp->s_addr & mask))
+ continue;
+
+ /* Copy out the local ethernet address */
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY((caddr_t) &arpcom.ac_enaddr, hwaddr->sa_data,
+ sizeof(arpcom.ac_enaddr));
+ return 1; /* success! */
+ }
+
+ /* couldn't find one */
+ return 0;
+}
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+int
+logwtmp(line, name, host)
+ char *line, *name, *host;
+{
+ int fd;
+ struct stat buf;
+ struct utmp ut;
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time(&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ close(fd);
+}
diff --git a/usr.sbin/pppd/sys-ultrix.c b/usr.sbin/pppd/sys-ultrix.c
new file mode 100644
index 0000000..ca8f2a4
--- /dev/null
+++ b/usr.sbin/pppd/sys-ultrix.c
@@ -0,0 +1,663 @@
+/*
+ * sys-ultrix.c - System-dependent procedures for setting up
+ * PPP interfaces on Ultrix systems.
+ *
+ * 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-ultrix.c,v 1.4 1994/05/25 06:30:49 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <syslog.h>
+#include <utmp.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+
+#include <net/if.h>
+
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include "pppd.h"
+#include "ppp.h"
+
+static int initdisc = -1; /* Initial TTY discipline */
+extern int kdebugflag;
+
+/*
+ * 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");
+ }
+}
+
+
+/*
+ * 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);
+ }
+}
+
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+ u_char *buf;
+{
+ int len;
+
+ if ((len = read(fd, buf, MTU + DLLHEADERLEN)) < 0) {
+ if (errno == EWOULDBLOCK) {
+ MAINDEBUG((LOG_DEBUG, "read(fd): EWOULDBLOCK"));
+ 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_long 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(s, 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_long 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();
+ }
+}
+
+/*
+ * 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.
+ */
+int
+sifup(u)
+{
+ struct ifreq ifr;
+ u_int x;
+
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ return 0;
+ }
+ ifr.ifr_flags |= IFF_UP;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+ return 0;
+ }
+ 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)
+{
+ struct ifreq ifr;
+ u_int x;
+ int rv;
+
+ rv = 1;
+ 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(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+ rv = 0;
+ } else {
+ ifr.ifr_flags &= ~IFF_UP;
+ if (ioctl(s, 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);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+{
+ int ret;
+ struct ifreq ifr;
+
+ ret = 1;
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = o;
+ if (ioctl(s, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFADDR): %m");
+ ret = 0;
+ }
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = h;
+ if (ioctl(s, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m");
+ ret = 0;
+ }
+ if (m != 0) {
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = m;
+ syslog(LOG_INFO, "Setting interface mask to %s\n", ip_ntoa(m));
+ if (ioctl(s, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCSIFNETMASK): %m");
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = h;
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = o;
+ rt.rt_flags = RTF_HOST;
+ if (ioctl(s, SIOCDELRT, (caddr_t) &rt) < 0) {
+ syslog(LOG_ERR, "ioctl(SIOCDELRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCADDRT, &rt) < 0) {
+ syslog(LOG_ERR, "default route ioctl(SIOCADDRT): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, g)
+{
+ struct rtentry rt;
+
+ SET_SA_FAMILY(rt.rt_dst, AF_INET);
+ SET_SA_FAMILY(rt.rt_gateway, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = g;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(s, SIOCDELRT, &rt) < 0)
+ syslog(LOG_WARNING, "default route ioctl(SIOCDELRT): %m");
+}
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+ int unit;
+ u_long hisaddr;
+{
+ struct arpreq arpreq;
+
+ BZERO(&arpreq, sizeof(arpreq));
+
+ /*
+ * Get the hardware address of an interface on the same subnet
+ * as our local address.
+ */
+ if (!get_ether_addr(hisaddr, &arpreq.arp_ha)) {
+ syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+ return 0;
+ }
+
+ 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(s, 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_long 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(s, SIOCDARP, (caddr_t)&arpreq) < 0) {
+ syslog(LOG_WARNING, "ioctl(SIOCDARP): %m");
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * 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_long ipaddr;
+ struct sockaddr *hwaddr;
+{
+ struct ifreq *ifr, *ifend, *ifp;
+ u_long 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(s, 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; ) {
+ 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(s, 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(s, SIOCGIFNETMASK, &ifreq) < 0)
+ continue;
+ mask = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+ if ((ipaddr & mask) != (ina & mask))
+ continue;
+
+ break;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
+);
+ }
+
+ if (ifr >= ifend)
+ return 0;
+ syslog(LOG_DEBUG, "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_DLI) {
+/* && ifr->ifr_addr.sa_family == AF_LINK) { Per! Kolla !!! ROHACK */
+ /*
+ * Found the link-level address - copy it out
+ */
+ dla = (struct sockaddr_dl *)&ifr->ifr_addr;
+ hwaddr->sa_family = AF_UNSPEC;
+ BCOPY(dla, hwaddr->sa_data, sizeof(hwaddr->sa_data));
+ return 1;
+ }
+ ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + sizeof(struct sockaddr)
+);
+ }
+
+ return 0;
+}
+
+
+/*
+ * 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;
+
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 1; /* can't tell - maybe we're not root */
+
+ strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+ ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+ close(s);
+
+ return ok;
+}
+
+
+/*
+ Seems like strdup() is not part of string package in Ultrix.
+ If I understood the man-page on the sun this should work.
+
+ Robert Olsson
+*/
+
+char *strdup( in ) char *in;
+{
+ char* dup;
+ if(! (dup = (char *) malloc( strlen( in ) +1 ))) return NULL;
+ (void) strcpy( dup, in );
+ return dup;
+}
+
+/*
+ * This logwtmp() implementation is subject to the following copyright:
+ *
+ * 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.
+ */
+
+#define WTMPFILE "/usr/adm/wtmp"
+
+int
+logwtmp(line, name, host)
+ char *line, *name, *host;
+{
+ int fd;
+ struct stat buf;
+ struct utmp ut;
+
+ if ((fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0)
+ return;
+ if (!fstat(fd, &buf)) {
+ (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
+ (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
+ (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
+ (void)time(&ut.ut_time);
+ if (write(fd, (char *)&ut, sizeof(struct utmp)) != sizeof(struct utmp))
+ (void)ftruncate(fd, buf.st_size);
+ }
+ close(fd);
+}
diff --git a/usr.sbin/pppd/upap.c b/usr.sbin/pppd/upap.c
new file mode 100644
index 0000000..61d22ac
--- /dev/null
+++ b/usr.sbin/pppd/upap.c
@@ -0,0 +1,561 @@
+/*
+ * 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.2 1994/04/11 07:13:44 paulus Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "ppp.h"
+#include "pppd.h"
+#include "upap.h"
+
+
+upap_state upap[NPPP]; /* UPAP state; one for each unit */
+
+
+static void upap_timeout __ARGS((caddr_t));
+static void upap_rauthreq __ARGS((upap_state *, u_char *, int, int));
+static void upap_rauthack __ARGS((upap_state *, u_char *, int, int));
+static void upap_rauthnak __ARGS((upap_state *, u_char *, int, int));
+static void upap_sauthreq __ARGS((upap_state *));
+static void upap_sresp __ARGS((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;
+}
+
+
+/*
+ * 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;
+}
+
+
+/*
+ * upap_timeout - Timeout 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, UPAP);
+ return;
+ }
+
+ upap_sauthreq(u); /* Send Authenticate-Request */
+}
+
+
+/*
+ * 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;
+}
+
+
+/*
+ * 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 */
+
+ 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, UPAP);
+ }
+ if (u->us_serverstate == UPAPSS_LISTEN) {
+ syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
+ auth_peer_fail(unit, UPAP);
+ }
+ 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, UPAP);
+ } else {
+ u->us_serverstate = UPAPSS_BADAUTH;
+ auth_peer_fail(u->us_unit, UPAP);
+ }
+}
+
+
+/*
+ * 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, UPAP);
+}
+
+
+/*
+ * 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, UPAP);
+}
+
+
+/*
+ * 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, UPAP);
+
+ 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 + DLLHEADERLEN);
+
+ 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, UPAP);
+
+ PUTCHAR(code, outp);
+ PUTCHAR(id, outp);
+ PUTSHORT(outlen, outp);
+ PUTCHAR(msglen, outp);
+ BCOPY(msg, outp, msglen);
+ output(u->us_unit, outpacket_buf, outlen + DLLHEADERLEN);
+
+ 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) __ARGS((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 0000000..10c3414
--- /dev/null
+++ b/usr.sbin/pppd/upap.h
@@ -0,0 +1,91 @@
+/*
+ * 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.2 1994/04/11 07:13:44 paulus 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 time in milliseconds */
+ int us_transmits; /* Number of auth-reqs sent */
+ int us_maxtransmits; /* Maximum number of auth-reqs to send */
+} 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 time in seconds */
+
+
+extern upap_state upap[];
+
+void upap_init __ARGS((int));
+void upap_authwithpeer __ARGS((int, char *, char *));
+void upap_authpeer __ARGS((int));
+void upap_lowerup __ARGS((int));
+void upap_lowerdown __ARGS((int));
+void upap_input __ARGS((int, u_char *, int));
+void upap_protrej __ARGS((int));
+int upap_printpkt __ARGS((u_char *, int,
+ void (*) __ARGS((void *, char *, ...)), void *));
diff --git a/usr.sbin/pstat/Makefile b/usr.sbin/pstat/Makefile
new file mode 100644
index 0000000..5018d43
--- /dev/null
+++ b/usr.sbin/pstat/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pstat
+CFLAGS+=-I/sys
+BINGRP= kmem
+BINMODE=2555
+DPADD= ${LIBKVM}
+LDADD= -lkvm
+MAN8= pstat.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pstat/pstat.8 b/usr.sbin/pstat/pstat.8
new file mode 100644
index 0000000..b2e8dec
--- /dev/null
+++ b/usr.sbin/pstat/pstat.8
@@ -0,0 +1,321 @@
+.\" Copyright (c) 1980, 1991, 1993, 1994
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" @(#)pstat.8 8.4 (Berkeley) 4/19/94
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)pstat.8 8.4 (Berkeley) 4/19/94
+.\"
+.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 Tfnstv
+.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 /kernel
+unless
+.Ar system
+is specified.
+The
+.Fl n
+option specifies that devices should be printed out by major/minor
+number rather than by name.
+.Pp
+Options are
+.Bl -tag -width indent
+.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 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 FILES
+.Bl -tag -width /dev/kmemxxx -compact
+.It Pa /kernel
+namelist
+.It Pa /dev/kmem
+default source of tables
+.El
+.Sh SEE ALSO
+.Xr iostat 1 ,
+.Xr ps 1 ,
+.Xr systat 1 ,
+.Xr vmstat 1 ,
+.Xr stat 2 ,
+.Xr fs 5 ,
+.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 0000000..0a3cdea
--- /dev/null
+++ b/usr.sbin/pstat/pstat.c
@@ -0,0 +1,1110 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)pstat.c 8.9 (Berkeley) 2/16/94";
+#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/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
+ { "_cons" },
+#define SPTY NLMANDATORY + 4
+ { "_pt_tty" },
+#define SNPTY NLMANDATORY + 5
+ { "_npty" },
+
+#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
+
+ { "" }
+};
+
+int usenumflag;
+int totalflag;
+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((struct tty *, 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:finstv")) != EOF)
+ 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 '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();
+ switch(ST.f_type) {
+ case MOUNT_UFS:
+ case MOUNT_MFS:
+ ufs_header();
+ break;
+ case MOUNT_NFS:
+ nfs_header();
+ break;
+ case MOUNT_NONE:
+ case MOUNT_MSDOS:
+ default:
+ break;
+ }
+ (void)printf("\n");
+ }
+ vnode_print(evp->avnode, vp);
+ switch(ST.f_type) {
+ case MOUNT_UFS:
+ case MOUNT_MFS:
+ ufs_print(vp);
+ break;
+ case MOUNT_NFS:
+ nfs_print(vp);
+ break;
+ case MOUNT_NONE:
+ case MOUNT_MSDOS:
+ default:
+ break;
+ }
+ (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 ");
+ switch (ST.f_type) {
+ case MOUNT_NONE:
+ type = "none";
+ break;
+ case MOUNT_UFS:
+ type = "ufs";
+ break;
+ case MOUNT_NFS:
+ type = "nfs";
+ break;
+ case MOUNT_MFS:
+ type = "mfs";
+ break;
+ case MOUNT_MSDOS:
+ type = "pc";
+ break;
+ default:
+ type = "unknown";
+ break;
+ }
+ (void)printf("%s %s on %s", type, 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.tqh_first;
+ mp != NULL; mp = mp->mnt_list.tqe_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++;
+ }
+ }
+ *avnodes = num;
+ return ((struct e_vnode *)vbuf);
+}
+
+char hdr[]=" LINE RAW CAN OUT HWT LWT COL STATE SESS PGID DISC\n";
+int ttyspace = 128;
+
+void
+ttymode()
+{
+ struct tty *tty;
+
+ if ((tty = malloc(ttyspace * sizeof(*tty))) == NULL)
+ err(1, NULL);
+#ifndef hp300
+ (void)printf("1 console\n");
+ KGET(SCONS, *tty);
+ (void)printf(hdr);
+ ttyprt(&tty[0], 0);
+#endif
+#ifdef vax
+ if (nl[SNQD].n_type != 0)
+ qdss();
+ if (nl[SNDZ].n_type != 0)
+ ttytype(tty, "dz", SDZ, SNDZ);
+ if (nl[SNDH].n_type != 0)
+ ttytype(tty, "dh", SDH, SNDH);
+ if (nl[SNDMF].n_type != 0)
+ ttytype(tty, "dmf", SDMF, SNDMF);
+ if (nl[SNDHU].n_type != 0)
+ ttytype(tty, "dhu", SDHU, SNDHU);
+ if (nl[SNDMZ].n_type != 0)
+ ttytype(tty, "dmz", SDMZ, SNDMZ);
+#endif
+#ifdef tahoe
+ if (nl[SNVX].n_type != 0)
+ ttytype(tty, "vx", SVX, SNVX);
+ if (nl[SNMP].n_type != 0)
+ ttytype(tty, "mp", SMP, SNMP);
+#endif
+#ifdef hp300
+ if (nl[SNITE].n_type != 0)
+ ttytype(tty, "ite", SITE, SNITE);
+ if (nl[SNDCA].n_type != 0)
+ ttytype(tty, "dca", SDCA, SNDCA);
+ if (nl[SNDCM].n_type != 0)
+ ttytype(tty, "dcm", SDCM, SNDCM);
+ if (nl[SNDCL].n_type != 0)
+ ttytype(tty, "dcl", SDCL, SNDCL);
+#endif
+#ifdef mips
+ if (nl[SNDC].n_type != 0)
+ ttytype(tty, "dc", SDC, SNDC);
+#endif
+ if (nl[SNPTY].n_type != 0)
+ ttytype(tty, "pty", SPTY, SNPTY);
+}
+
+void
+ttytype(tty, name, type, number)
+ register struct tty *tty;
+ char *name;
+ int type, number;
+{
+ register struct tty *tp;
+ int ntty;
+
+ if (tty == NULL)
+ return;
+ KGET(number, ntty);
+ (void)printf("%d %s %s\n", ntty, name, (ntty == 1) ? "line" : "lines");
+ if (ntty > ttyspace) {
+ ttyspace = ntty;
+ if ((tty = realloc(tty, ttyspace * sizeof(*tty))) == 0)
+ err(1, NULL);
+ }
+ KGET1(type, tty, ntty * sizeof(struct tty), "tty structs");
+ (void)printf(hdr);
+ for (tp = tty; tp < &tty[ntty]; tp++)
+ ttyprt(tp, tp - tty);
+}
+
+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("%2d %3d ", tp->t_rawq.c_cc, tp->t_canq.c_cc);
+ (void)printf("%3d %4d %3d %3d ", 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("%-4s %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;
+ 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 file **)buf);
+ fp = (struct file *)(buf + sizeof(struct file *));
+ nfile = (len - sizeof(struct file *)) / 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_filef, 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;
+ }
+ }
+
+ 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 -Tfnstv [system] [-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 0000000..86116fec
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= pwd_mkdb
+SRCS= pw_scan.c pwd_mkdb.c
+MAN8= pwd_mkdb.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/pwd_mkdb/pw_scan.c b/usr.sbin/pwd_mkdb/pw_scan.c
new file mode 100644
index 0000000..fbefc5b
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pw_scan.c
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_scan.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This module is used to "verify" password entries by chpass(1) and
+ * pwd_mkdb(8).
+ */
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "pw_scan.h"
+
+int
+pw_scan(bp, pw)
+ char *bp;
+ struct passwd *pw;
+{
+ long id;
+ int root;
+ char *p, *sh;
+
+ pw->pw_fields = 0;
+ if (!(pw->pw_name = strsep(&bp, ":"))) /* login */
+ goto fmt;
+ root = !strcmp(pw->pw_name, "root");
+ if(pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0'))
+ pw->pw_fields |= _PWF_NAME;
+
+ if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */
+ goto fmt;
+ if(pw->pw_passwd[0]) pw->pw_fields |= _PWF_PASSWD;
+
+ if (!(p = strsep(&bp, ":"))) /* uid */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_UID;
+ id = atol(p);
+ if (root && id) {
+ warnx("root uid should be 0");
+ return (0);
+ }
+ if (id > USHRT_MAX) {
+ warnx("%s > max uid value (%d)", p, USHRT_MAX);
+ return (0);
+ }
+ pw->pw_uid = id;
+
+ if (!(p = strsep(&bp, ":"))) /* gid */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_GID;
+ id = atol(p);
+ if (id > USHRT_MAX) {
+ warnx("%s > max gid value (%d)", p, USHRT_MAX);
+ return (0);
+ }
+ pw->pw_gid = id;
+
+ pw->pw_class = strsep(&bp, ":"); /* class */
+ if(pw->pw_class[0]) pw->pw_fields |= _PWF_CLASS;
+
+ if (!(p = strsep(&bp, ":"))) /* change */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_CHANGE;
+ pw->pw_change = atol(p);
+
+ if (!(p = strsep(&bp, ":"))) /* expire */
+ goto fmt;
+ if(p[0]) pw->pw_fields |= _PWF_EXPIRE;
+ pw->pw_expire = atol(p);
+
+ pw->pw_gecos = strsep(&bp, ":"); /* gecos */
+ if(pw->pw_gecos[0]) pw->pw_fields |= _PWF_GECOS;
+
+ pw->pw_dir = strsep(&bp, ":"); /* directory */
+ if(pw->pw_dir[0]) pw->pw_fields |= _PWF_DIR;
+
+ 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[0]) pw->pw_fields |= _PWF_SHELL;
+
+ 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 0000000..d1d4bc1
--- /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 *));
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8
new file mode 100644
index 0000000..6a55fcb
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8
@@ -0,0 +1,132 @@
+.\" 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.
+.\"
+.\" @(#)pwd_mkdb.8 8.1 (Berkeley) 6/6/93
+.\"
+.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
+.Op Fl d Ar directory
+.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 .
+.It Fl d
+Store databases into specified destination directory instead of
+.Dq Pa /etc .
+.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/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.
+.It Pa /etc/master.passwd
+The current password file.
+.It Pa /etc/passwd
+A Version 7 format password 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 0000000..9c1ecc7
--- /dev/null
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -0,0 +1,427 @@
+/*-
+ * 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
+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[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94";
+#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)
+
+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 */
+static char prefix[MAXPATHLEN];
+
+void cleanup __P((void));
+void error __P((char *));
+void mv __P((char *, char *));
+int scan __P((FILE *, struct passwd *));
+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, yp_enabled = 0;
+ char *p, *t;
+ char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
+ char buf2[MAXPATHLEN];
+
+ strcpy(prefix, _PATH_PWD);
+ makeold = 0;
+ while ((ch = getopt(argc, argv, "d:pv")) != EOF)
+ switch(ch) {
+ case 'd':
+ strcpy(prefix, optarg);
+ break;
+ 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/%s.tmp", prefix, _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.)
+ */
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+ for (cnt = 1; scan(fp, &pwd); ++cnt) {
+ if(pwd.pw_name[0] == '+') {
+ if(pwd.pw_name[1] && !yp_enabled) {
+ yp_enabled = 1;
+ } else if(!pwd.pw_name[1]) {
+ yp_enabled = -1;
+ }
+ }
+#define COMPACT(e) t = e; while (*p++ = *t++);
+ /* 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, &pwd.pw_fields, sizeof pwd.pw_fields);
+ p += sizeof pwd.pw_fields;
+ 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);
+ }
+ /* If YP enabled, set flag. */
+ if(yp_enabled) {
+ buf[0] = yp_enabled + 2;
+ data.size = 1;
+ tbuf[0] = _PW_KEYYPENABLED;
+ key.size = 1;
+ if ((dp->put)(dp, &key, &data, 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/%s.tmp", prefix, _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); ++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, &pwd.pw_fields, sizeof pwd.pw_fields);
+ p += sizeof pwd.pw_fields;
+ 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");
+ }
+ /* If YP enabled, set flag. */
+ if(yp_enabled) {
+ buf[0] = yp_enabled + 2;
+ data.size = 1;
+ tbuf[0] = _PW_KEYYPENABLED;
+ key.size = 1;
+ if ((dp->put)(dp, &key, &data, 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/%s.tmp", prefix, _MP_DB);
+ (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
+ mv(buf, buf2);
+ (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
+ (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB);
+ mv(buf, buf2);
+ if (makeold) {
+ (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD);
+ (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
+ mv(buf, buf2);
+ }
+ /*
+ * 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.
+ */
+ (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD);
+ mv(pname, buf);
+ exit(0);
+}
+
+int
+scan(fp, pw)
+ FILE *fp;
+ struct passwd *pw;
+{
+ 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)) {
+ 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/%s.tmp", prefix, _SMP_DB);
+ (void)unlink(buf);
+ /* FALLTHROUGH */
+ case FILE_INSECURE:
+ (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
+ (void)unlink(buf);
+ }
+}
+
+void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: pwd_mkdb [-p] [-d <dest dir>] file\n");
+ exit(1);
+}
diff --git a/usr.sbin/quot/quot.8 b/usr.sbin/quot/quot.8
new file mode 100644
index 0000000..b1aefde
--- /dev/null
+++ b/usr.sbin/quot/quot.8
@@ -0,0 +1,84 @@
+.\" 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.
+.\"
+.\" @(#)quot.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.Dt QUOT 8
+.Os BSD 4
+.Sh NAME
+.Nm quot
+.Nd display total block usage per user for a file system
+.Sh SYNOPSIS
+.Nm quot
+.Op Fl ncf
+.Op Ar filesystem Ar ...
+.Sh DESCRIPTION
+The
+.Nm quot
+command
+displays the total count of blocks owned by a user for the filesystem
+.Ar filesystem .
+If the filesystem option
+.Ar filesystem
+is not specified,
+the file systems listed in
+.Pa /etc/fstab
+are used.
+The following options are available:
+.Bl -tag -width Ds
+.It Fl c
+Display information on file size and block usage. The file sizes
+are listed in the first column, the second column contains a count
+of how many files of that size were found and the third column
+lists the cumulative block usage for the displayed size and all smaller
+files.
+.It Fl f
+For each user,
+the number of files (inodes) owned is displayed in addition
+to the block usage.
+.It Fl n
+A list sorted by block usage is displayed.
+This is the result of
+.Nm quot
+executing the following command:
+.Bd -literal -offset indent
+ncheck filesystem \&| sort +0n \&| quot \-n filesystem
+.Ed
+.El
+.Sh SEE ALSO
+.Xr ls 1 ,
+.Xr du 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.At 32v .
diff --git a/usr.sbin/quotaon/Makefile b/usr.sbin/quotaon/Makefile
new file mode 100644
index 0000000..be3001e
--- /dev/null
+++ b/usr.sbin/quotaon/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= quotaon
+MAN8= 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 0000000..8c68d76
--- /dev/null
+++ b/usr.sbin/quotaon/quotaon.8
@@ -0,0 +1,139 @@
+.\" 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.
+.\"
+.\" @(#)quotaon.8 8.2 (Berkeley) 12/11/93
+.\"
+.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 0000000..8eabd27
--- /dev/null
+++ b/usr.sbin/quotaon/quotaon.c
@@ -0,0 +1,251 @@
+/*
+ * 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[] = "@(#)quotaon.c 8.1 (Berkeley) 6/6/93";
+#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 <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/repquota/Makefile b/usr.sbin/repquota/Makefile
new file mode 100644
index 0000000..eea7351
--- /dev/null
+++ b/usr.sbin/repquota/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= repquota
+MAN8= 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 0000000..6fba8e1
--- /dev/null
+++ b/usr.sbin/repquota/repquota.8
@@ -0,0 +1,103 @@
+.\" 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.
+.\"
+.\" @(#)repquota.8 8.1 (Berkeley) 6/6/93
+.\"
+.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 0000000..29989eb
--- /dev/null
+++ b/usr.sbin/repquota/repquota.c
@@ -0,0 +1,379 @@
+/*
+ * 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[] = "@(#)repquota.c 8.1 (Berkeley) 6/6/93";
+#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 <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 0000000..7c7f40c
--- /dev/null
+++ b/usr.sbin/rmt/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= rmt
+MAN8= 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 0000000..fae5628
--- /dev/null
+++ b/usr.sbin/rmt/rmt.8
@@ -0,0 +1,217 @@
+.\" 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.
+.\"
+.\" @(#)rmt.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.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 should be discouraged from using this for a remote
+file access protocol.
+.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 0000000..098e502
--- /dev/null
+++ b/usr.sbin/rmt/rmt.c
@@ -0,0 +1,244 @@
+/*
+ * 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[] = "@(#)rmt.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mtio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sgtty.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+
+#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)
+
+char *checkbuf __P((char *, int));
+void error __P((int));
+void getstring __P((char *));
+
+int
+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));
+ 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, (off_t)atol(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;
+}
+
+void
+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;
+{
+
+ 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);
+}
+
+void
+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/routed/Makefile b/usr.sbin/routed/Makefile
new file mode 100644
index 0000000..b2bdbf3
--- /dev/null
+++ b/usr.sbin/routed/Makefile
@@ -0,0 +1,22 @@
+# @(#)Makefile 8.1 (Berkeley) 6/19/93
+
+PROG= routed
+SRCS= af.c if.c input.c main.c output.c startup.c tables.c timer.c \
+ trace.c inet.c
+MAN8= routed.8
+#SUBDIR= query trace
+DPADD= ${LIBCOMPAT}
+LDADD= -lcompat
+
+.include <bsd.prog.mk>
+
+.if (${MACHINE} == "vax")
+# The following can be deleted where not appropriate to use the kernel's
+# inline code expansions.
+INLINE= /sys/vax/inline/obj/inline
+C2= /usr/libexec/c2
+.c.o:
+ ${CC} -S ${CFLAGS} ${.CURDIR}/${.PREFIX}.c
+ @${C2} ${.PREFIX}.s | ${INLINE} | ${AS} -o ${.PREFIX}.o
+ @rm -f ${.PREFIX}.s
+.endif
diff --git a/usr.sbin/routed/af.c b/usr.sbin/routed/af.c
new file mode 100644
index 0000000..05bf8fa
--- /dev/null
+++ b/usr.sbin/routed/af.c
@@ -0,0 +1,171 @@
+/*
+ * 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[] = "@(#)af.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include "defs.h"
+
+/*
+ * Address family support routines
+ */
+int inet_hash(), inet_netmatch(), inet_output(),
+ inet_portmatch(), inet_portcheck(),
+ inet_checkhost(), inet_rtflags(), inet_sendroute(), inet_canon();
+char *inet_format();
+
+#define NIL { 0 }
+#define INET \
+ { inet_hash, inet_netmatch, inet_output, \
+ inet_portmatch, inet_portcheck, inet_checkhost, \
+ inet_rtflags, inet_sendroute, inet_canon, \
+ inet_format \
+ }
+
+struct afswitch afswitch[AF_MAX] = {
+ NIL, /* 0- unused */
+ NIL, /* 1- Unix domain, unused */
+ INET, /* Internet */
+};
+
+int af_max = sizeof(afswitch) / sizeof(afswitch[0]);
+
+struct sockaddr_in inet_default = {
+#ifdef RTM_ADD
+ sizeof (inet_default),
+#endif
+ AF_INET, INADDR_ANY };
+
+inet_hash(sin, hp)
+ register struct sockaddr_in *sin;
+ struct afhash *hp;
+{
+ register u_long n;
+
+ n = inet_netof(sin->sin_addr);
+ if (n)
+ while ((n & 0xff) == 0)
+ n >>= 8;
+ hp->afh_nethash = n;
+ hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
+ hp->afh_hosthash &= 0x7fffffff;
+}
+
+inet_netmatch(sin1, sin2)
+ struct sockaddr_in *sin1, *sin2;
+{
+
+ return (inet_netof(sin1->sin_addr) == inet_netof(sin2->sin_addr));
+}
+
+/*
+ * Verify the message is from the right port.
+ */
+inet_portmatch(sin)
+ register struct sockaddr_in *sin;
+{
+
+ return (sin->sin_port == sp->s_port);
+}
+
+/*
+ * Verify the message is from a "trusted" port.
+ */
+inet_portcheck(sin)
+ struct sockaddr_in *sin;
+{
+
+ return (ntohs(sin->sin_port) <= IPPORT_RESERVED);
+}
+
+/*
+ * Internet output routine.
+ */
+inet_output(s, flags, sin, size)
+ int s, flags;
+ struct sockaddr_in *sin;
+ int size;
+{
+ struct sockaddr_in dst;
+
+ dst = *sin;
+ sin = &dst;
+ if (sin->sin_port == 0)
+ sin->sin_port = sp->s_port;
+ if (sin->sin_len == 0)
+ sin->sin_len = sizeof (*sin);
+ if (sendto(s, packet, size, flags,
+ (struct sockaddr *)sin, sizeof (*sin)) < 0)
+ perror("sendto");
+}
+
+/*
+ * Return 1 if the address is believed
+ * for an Internet host -- THIS IS A KLUDGE.
+ */
+inet_checkhost(sin)
+ struct sockaddr_in *sin;
+{
+ u_long i = ntohl(sin->sin_addr.s_addr);
+
+#ifndef IN_EXPERIMENTAL
+#define IN_EXPERIMENTAL(i) (((long) (i) & 0xe0000000) == 0xe0000000)
+#endif
+
+ if (IN_EXPERIMENTAL(i) || sin->sin_port != 0)
+ return (0);
+ if (i != 0 && (i & 0xff000000) == 0)
+ return (0);
+ for (i = 0; i < sizeof(sin->sin_zero)/sizeof(sin->sin_zero[0]); i++)
+ if (sin->sin_zero[i])
+ return (0);
+ return (1);
+}
+
+inet_canon(sin)
+ struct sockaddr_in *sin;
+{
+
+ sin->sin_port = 0;
+ sin->sin_len = sizeof(*sin);
+}
+
+char *
+inet_format(sin)
+ struct sockaddr_in *sin;
+{
+ char *inet_ntoa();
+
+ return (inet_ntoa(sin->sin_addr));
+}
diff --git a/usr.sbin/routed/af.h b/usr.sbin/routed/af.h
new file mode 100644
index 0000000..2fff298
--- /dev/null
+++ b/usr.sbin/routed/af.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ *
+ * @(#)af.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Per address family routines.
+ */
+struct afswitch {
+ int (*af_hash)(); /* returns keys based on address */
+ int (*af_netmatch)(); /* verifies net # matching */
+ int (*af_output)(); /* interprets address for sending */
+ int (*af_portmatch)(); /* packet from some other router? */
+ int (*af_portcheck)(); /* packet from privileged peer? */
+ int (*af_checkhost)(); /* tells if address is valid */
+ int (*af_rtflags)(); /* get flags for route (host or net) */
+ int (*af_sendroute)(); /* check bounds of subnet broadcast */
+ int (*af_canon)(); /* canonicalize address for compares */
+ char *(*af_format)(); /* convert address to string */
+};
+
+/*
+ * Structure returned by af_hash routines.
+ */
+struct afhash {
+ u_int afh_hosthash; /* host based hash */
+ u_int afh_nethash; /* network based hash */
+};
+
+extern struct afswitch afswitch[]; /* table proper */
+extern int af_max; /* number of entries in table */
diff --git a/usr.sbin/routed/defs.h b/usr.sbin/routed/defs.h
new file mode 100644
index 0000000..5672210
--- /dev/null
+++ b/usr.sbin/routed/defs.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)defs.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Internal data structure definitions for
+ * user routing process. Based on Xerox NS
+ * protocol specs with mods relevant to more
+ * general addressing scheme.
+ */
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#include <net/route.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+
+#include <stdio.h>
+#include <netdb.h>
+
+#include "trace.h"
+#include "interface.h"
+#include "table.h"
+#include "af.h"
+
+/*
+ * When we find any interfaces marked down we rescan the
+ * kernel every CHECK_INTERVAL seconds to see if they've
+ * come up.
+ */
+#define CHECK_INTERVAL (1*60)
+
+#define equal(a1, a2) \
+ (bcmp((caddr_t)(a1), (caddr_t)(a2), sizeof (struct sockaddr)) == 0)
+
+struct sockaddr_in addr; /* address of daemon's socket */
+
+int s; /* source and sink of all data */
+int r; /* routing socket */
+pid_t pid; /* process id for identifying messages */
+uid_t uid; /* user id for identifying messages */
+int seqno; /* sequence number for identifying messages */
+int kmem;
+int supplier; /* process should supply updates */
+int install; /* if 1 call kernel */
+int lookforinterfaces; /* if 1 probe kernel for new up interfaces */
+int performnlist; /* if 1 check if /kernel has changed */
+int externalinterfaces; /* # of remote and local interfaces */
+struct timeval now; /* current idea of time */
+struct timeval lastbcast; /* last time all/changes broadcast */
+struct timeval lastfullupdate; /* last time full table broadcast */
+struct timeval nextbcast; /* time to wait before changes broadcast */
+int needupdate; /* true if we need update at nextbcast */
+
+char packet[MAXPACKETSIZE+1];
+struct rip *msg;
+
+char **argv0;
+struct servent *sp;
+
+struct in_addr inet_makeaddr();
+int inet_addr();
+int inet_maskof();
+int sndmsg();
+int supply();
+int cleanup();
+
+int rtioctl();
+#define ADD 1
+#define DELETE 2
+#define CHANGE 3
diff --git a/usr.sbin/routed/if.c b/usr.sbin/routed/if.c
new file mode 100644
index 0000000..54e8705
--- /dev/null
+++ b/usr.sbin/routed/if.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 sccsid[] = "@(#)if.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Find the interface with address addr.
+ */
+struct interface *
+if_ifwithaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+#define same(a1, a2) \
+ (bcmp((caddr_t)((a1)->sa_data), (caddr_t)((a2)->sa_data), 14) == 0)
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (ifp->int_addr.sa_family != addr->sa_family)
+ continue;
+ if (same(&ifp->int_addr, addr))
+ break;
+ if ((ifp->int_flags & IFF_BROADCAST) &&
+ same(&ifp->int_broadaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the point-to-point interface with destination address addr.
+ */
+struct interface *
+if_ifwithdstaddr(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if ((ifp->int_flags & IFF_POINTOPOINT) == 0)
+ continue;
+ if (same(&ifp->int_dstaddr, addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find the interface on the network
+ * of the specified address.
+ */
+struct interface *
+if_ifwithnet(addr)
+ register struct sockaddr *addr;
+{
+ register struct interface *ifp;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= af_max)
+ return (0);
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_REMOTE)
+ continue;
+ if (af != ifp->int_addr.sa_family)
+ continue;
+ if ((*netmatch)(addr, &ifp->int_addr))
+ break;
+ }
+ return (ifp);
+}
+
+/*
+ * Find an interface from which the specified address
+ * should have come from. Used for figuring out which
+ * interface a packet came in on -- for tracing.
+ */
+struct interface *
+if_iflookup(addr)
+ struct sockaddr *addr;
+{
+ register struct interface *ifp, *maybe;
+ register int af = addr->sa_family;
+ register int (*netmatch)();
+
+ if (af >= af_max)
+ return (0);
+ maybe = 0;
+ netmatch = afswitch[af].af_netmatch;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_addr.sa_family != af)
+ continue;
+ if (same(&ifp->int_addr, addr))
+ break;
+ if ((ifp->int_flags & IFF_BROADCAST) &&
+ same(&ifp->int_broadaddr, addr))
+ break;
+ if ((ifp->int_flags & IFF_POINTOPOINT) &&
+ same(&ifp->int_dstaddr, addr))
+ break;
+ if (maybe == 0 && (*netmatch)(addr, &ifp->int_addr))
+ maybe = ifp;
+ }
+ if (ifp == 0)
+ ifp = maybe;
+ return (ifp);
+}
diff --git a/usr.sbin/routed/inet.c b/usr.sbin/routed/inet.c
new file mode 100644
index 0000000..925472c
--- /dev/null
+++ b/usr.sbin/routed/inet.c
@@ -0,0 +1,243 @@
+/*
+ * 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[] = "@(#)inet.c 8.2 (Berkeley) 8/14/93";
+#endif /* not lint */
+
+/*
+ * Temporarily, copy these routines from the kernel,
+ * as we need to know about subnets.
+ */
+#include "defs.h"
+
+extern struct interface *ifnet;
+
+/*
+ * Formulate an Internet address from network + host.
+ */
+struct in_addr
+inet_makeaddr(net, host)
+ u_long net, host;
+{
+ register struct interface *ifp;
+ register u_long mask;
+ u_long addr;
+
+ if (IN_CLASSA(net))
+ mask = IN_CLASSA_HOST;
+ else if (IN_CLASSB(net))
+ mask = IN_CLASSB_HOST;
+ else
+ mask = IN_CLASSC_HOST;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net) {
+ mask = ~ifp->int_subnetmask;
+ break;
+ }
+ addr = net | (host & mask);
+ addr = htonl(addr);
+ return (*(struct in_addr *)&addr);
+}
+
+/*
+ * Return the network number from an internet address.
+ */
+inet_netof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+ register u_long net;
+ register struct interface *ifp;
+
+ if (IN_CLASSA(i))
+ net = i & IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ net = i & IN_CLASSB_NET;
+ else
+ net = i & IN_CLASSC_NET;
+
+ /*
+ * Check whether network is a subnet;
+ * if so, return subnet number.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net)
+ return (i & ifp->int_subnetmask);
+ return (net);
+}
+
+/*
+ * Return the host portion of an internet address.
+ */
+inet_lnaof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+ register u_long net, host;
+ register struct interface *ifp;
+
+ if (IN_CLASSA(i)) {
+ net = i & IN_CLASSA_NET;
+ host = i & IN_CLASSA_HOST;
+ } else if (IN_CLASSB(i)) {
+ net = i & IN_CLASSB_NET;
+ host = i & IN_CLASSB_HOST;
+ } else {
+ net = i & IN_CLASSC_NET;
+ host = i & IN_CLASSC_HOST;
+ }
+
+ /*
+ * Check whether network is a subnet;
+ * if so, use the modified interpretation of `host'.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & net) == ifp->int_net)
+ return (host &~ ifp->int_subnetmask);
+ return (host);
+}
+
+/*
+ * Return the netmask pertaining to an internet address.
+ */
+inet_maskof(inaddr)
+ u_long inaddr;
+{
+ register u_long i = ntohl(inaddr);
+ register u_long mask;
+ register struct interface *ifp;
+
+ if (i == 0) {
+ mask = 0;
+ } else if (IN_CLASSA(i)) {
+ mask = IN_CLASSA_NET;
+ } else if (IN_CLASSB(i)) {
+ mask = i & IN_CLASSB_NET;
+ } else
+ mask = i & IN_CLASSC_NET;
+
+ /*
+ * Check whether network is a subnet;
+ * if so, use the modified interpretation of `host'.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if ((ifp->int_netmask & i) == ifp->int_net)
+ mask = ifp->int_subnetmask;
+ return (htonl(mask));
+}
+
+/*
+ * Return RTF_HOST if the address is
+ * for an Internet host, RTF_SUBNET for a subnet,
+ * 0 for a network.
+ */
+inet_rtflags(sin)
+ struct sockaddr_in *sin;
+{
+ register u_long i = ntohl(sin->sin_addr.s_addr);
+ register u_long net, host;
+ register struct interface *ifp;
+
+ if (IN_CLASSA(i)) {
+ net = i & IN_CLASSA_NET;
+ host = i & IN_CLASSA_HOST;
+ } else if (IN_CLASSB(i)) {
+ net = i & IN_CLASSB_NET;
+ host = i & IN_CLASSB_HOST;
+ } else {
+ net = i & IN_CLASSC_NET;
+ host = i & IN_CLASSC_HOST;
+ }
+
+ /*
+ * Check whether this network is subnetted;
+ * if so, check whether this is a subnet or a host.
+ */
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if (net == ifp->int_net) {
+ if (host &~ ifp->int_subnetmask)
+ return (RTF_HOST);
+ else if (ifp->int_subnetmask != ifp->int_netmask)
+ return (RTF_SUBNET);
+ else
+ return (0); /* network */
+ }
+ if (host == 0)
+ return (0); /* network */
+ else
+ return (RTF_HOST);
+}
+
+/*
+ * Return true if a route to subnet/host of route rt should be sent to dst.
+ * Send it only if dst is on the same logical network if not "internal",
+ * otherwise only if the route is the "internal" route for the logical net.
+ */
+inet_sendroute(rt, dst)
+ struct rt_entry *rt;
+ struct sockaddr_in *dst;
+{
+ register u_long r =
+ ntohl(((struct sockaddr_in *)&rt->rt_dst)->sin_addr.s_addr);
+ register u_long d = ntohl(dst->sin_addr.s_addr);
+
+ if (IN_CLASSA(r)) {
+ if ((r & IN_CLASSA_NET) == (d & IN_CLASSA_NET)) {
+ if ((r & IN_CLASSA_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSA_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ } else if (IN_CLASSB(r)) {
+ if ((r & IN_CLASSB_NET) == (d & IN_CLASSB_NET)) {
+ if ((r & IN_CLASSB_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSB_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ } else {
+ if ((r & IN_CLASSC_NET) == (d & IN_CLASSC_NET)) {
+ if ((r & IN_CLASSC_HOST) == 0)
+ return ((rt->rt_state & RTS_INTERNAL) == 0);
+ return (1);
+ }
+ if (r & IN_CLASSC_HOST)
+ return (0);
+ return ((rt->rt_state & RTS_INTERNAL) != 0);
+ }
+}
diff --git a/usr.sbin/routed/input.c b/usr.sbin/routed/input.c
new file mode 100644
index 0000000..fb0ee79
--- /dev/null
+++ b/usr.sbin/routed/input.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)input.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/syslog.h>
+
+/*
+ * Process a newly received packet.
+ */
+rip_input(from, rip, size)
+ struct sockaddr *from;
+ register struct rip *rip;
+ int size;
+{
+ register struct rt_entry *rt;
+ register struct netinfo *n;
+ register struct interface *ifp;
+ struct interface *if_ifwithdstaddr();
+ int count, changes = 0;
+ register struct afswitch *afp;
+ static struct sockaddr badfrom, badfrom2;
+
+ ifp = 0;
+ TRACE_INPUT(ifp, from, (char *)rip, size);
+ if (from->sa_family >= af_max ||
+ (afp = &afswitch[from->sa_family])->af_hash == (int (*)())0) {
+ syslog(LOG_INFO,
+ "\"from\" address in unsupported address family (%d), cmd %d\n",
+ from->sa_family, rip->rip_cmd);
+ return;
+ }
+ if (rip->rip_vers == 0) {
+ syslog(LOG_ERR,
+ "RIP version 0 packet received from %s! (cmd %d)",
+ (*afswitch[from->sa_family].af_format)(from), rip->rip_cmd);
+ return;
+ }
+ switch (rip->rip_cmd) {
+
+ case RIPCMD_REQUEST:
+ n = rip->rip_nets;
+ count = size - ((char *)n - (char *)rip);
+ if (count < sizeof (struct netinfo))
+ return;
+ for (; count > 0; n++) {
+ if (count < sizeof (struct netinfo))
+ break;
+ count -= sizeof (struct netinfo);
+
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+ n->rip_dst.sa_family =
+ ntohs(osa(n->rip_dst)->sa_family);
+ n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+ n->rip_metric = ntohl(n->rip_metric);
+ /*
+ * A single entry with sa_family == AF_UNSPEC and
+ * metric ``infinity'' means ``all routes''.
+ * We respond to routers only if we are acting
+ * as a supplier, or to anyone other than a router
+ * (eg, query).
+ */
+ if (n->rip_dst.sa_family == AF_UNSPEC &&
+ n->rip_metric == HOPCNT_INFINITY && count == 0) {
+ if (supplier || (*afp->af_portmatch)(from) == 0)
+ supply(from, 0, 0, 0);
+ return;
+ }
+ if (n->rip_dst.sa_family < af_max &&
+ afswitch[n->rip_dst.sa_family].af_hash)
+ rt = rtlookup(&n->rip_dst);
+ else
+ rt = 0;
+#define min(a, b) (a < b ? a : b)
+ n->rip_metric = rt == 0 ? HOPCNT_INFINITY :
+ min(rt->rt_metric + 1, HOPCNT_INFINITY);
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+ osa(n->rip_dst)->sa_family =
+ htons(n->rip_dst.sa_family);
+#endif
+ n->rip_metric = htonl(n->rip_metric);
+ }
+ rip->rip_cmd = RIPCMD_RESPONSE;
+ bcopy((char *)rip, packet, size);
+ (*afp->af_output)(s, 0, from, size);
+ return;
+
+ case RIPCMD_TRACEON:
+ case RIPCMD_TRACEOFF:
+ /* verify message came from a privileged port */
+ if ((*afp->af_portcheck)(from) == 0)
+ return;
+ if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+ (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+ ifp->int_flags & IFF_PASSIVE) {
+ syslog(LOG_ERR, "trace command from unknown router, %s",
+ (*afswitch[from->sa_family].af_format)(from));
+ return;
+ }
+ ((char *)rip)[size] = '\0';
+ if (rip->rip_cmd == RIPCMD_TRACEON)
+ traceon(rip->rip_tracefile);
+ else
+ traceoff();
+ return;
+
+ case RIPCMD_RESPONSE:
+ /* verify message came from a router */
+ if ((*afp->af_portmatch)(from) == 0)
+ return;
+ (*afp->af_canon)(from);
+ /* are we talking to ourselves? */
+ ifp = if_ifwithaddr(from);
+ if (ifp) {
+ if (ifp->int_flags & IFF_PASSIVE) {
+ syslog(LOG_ERR,
+ "bogus input (from passive interface, %s)",
+ (*afswitch[from->sa_family].af_format)(from));
+ return;
+ }
+ rt = rtfind(from);
+ if (rt == 0 || ((rt->rt_state & RTS_INTERFACE) == 0) &&
+ rt->rt_metric >= ifp->int_metric)
+ addrouteforif(ifp);
+ else
+ rt->rt_timer = 0;
+ return;
+ }
+ /*
+ * Update timer for interface on which the packet arrived.
+ * If from other end of a point-to-point link that isn't
+ * in the routing tables, (re-)add the route.
+ */
+ if ((rt = rtfind(from)) &&
+ (rt->rt_state & (RTS_INTERFACE | RTS_REMOTE)))
+ rt->rt_timer = 0;
+ else if ((ifp = if_ifwithdstaddr(from)) &&
+ (rt == 0 || rt->rt_metric >= ifp->int_metric))
+ addrouteforif(ifp);
+ /*
+ * "Authenticate" router from which message originated.
+ * We accept routing packets from routers directly connected
+ * via broadcast or point-to-point networks,
+ * and from those listed in /etc/gateways.
+ */
+ if ((ifp = if_iflookup(from)) == 0 || (ifp->int_flags &
+ (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0 ||
+ ifp->int_flags & IFF_PASSIVE) {
+ if (bcmp((char *)from, (char *)&badfrom,
+ sizeof(badfrom)) != 0) {
+ syslog(LOG_ERR,
+ "packet from unknown router, %s",
+ (*afswitch[from->sa_family].af_format)(from));
+ badfrom = *from;
+ }
+ return;
+ }
+ size -= 4 * sizeof (char);
+ n = rip->rip_nets;
+ for (; size > 0; size -= sizeof (struct netinfo), n++) {
+ if (size < sizeof (struct netinfo))
+ break;
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family =
+ ntohs(n->rip_dst.sa_family);
+#else
+ n->rip_dst.sa_family =
+ ntohs(osa(n->rip_dst)->sa_family);
+ n->rip_dst.sa_len = sizeof(n->rip_dst);
+#endif
+ n->rip_metric = ntohl(n->rip_metric);
+ if (n->rip_dst.sa_family >= af_max ||
+ (afp = &afswitch[n->rip_dst.sa_family])->af_hash ==
+ (int (*)())0) {
+ syslog(LOG_INFO,
+ "route in unsupported address family (%d), from %s (af %d)\n",
+ n->rip_dst.sa_family,
+ (*afswitch[from->sa_family].af_format)(from),
+ from->sa_family);
+ continue;
+ }
+ if (((*afp->af_checkhost)(&n->rip_dst)) == 0) {
+ syslog(LOG_DEBUG,
+ "bad host in route from %s (af %d)\n",
+ (*afswitch[from->sa_family].af_format)(from),
+ from->sa_family);
+ continue;
+ }
+ if (n->rip_metric == 0 ||
+ (unsigned) n->rip_metric > HOPCNT_INFINITY) {
+ if (bcmp((char *)from, (char *)&badfrom2,
+ sizeof(badfrom2)) != 0) {
+ syslog(LOG_ERR,
+ "bad metric (%d) from %s\n",
+ n->rip_metric,
+ (*afswitch[from->sa_family].af_format)(from));
+ badfrom2 = *from;
+ }
+ continue;
+ }
+ /*
+ * Adjust metric according to incoming interface.
+ */
+ if ((unsigned) n->rip_metric < HOPCNT_INFINITY)
+ n->rip_metric += ifp->int_metric;
+ if ((unsigned) n->rip_metric > HOPCNT_INFINITY)
+ n->rip_metric = HOPCNT_INFINITY;
+ rt = rtlookup(&n->rip_dst);
+ if (rt == 0 ||
+ (rt->rt_state & (RTS_INTERNAL|RTS_INTERFACE)) ==
+ (RTS_INTERNAL|RTS_INTERFACE)) {
+ /*
+ * If we're hearing a logical network route
+ * back from a peer to which we sent it,
+ * ignore it.
+ */
+ if (rt && rt->rt_state & RTS_SUBNET &&
+ (*afp->af_sendroute)(rt, from))
+ continue;
+ if ((unsigned)n->rip_metric < HOPCNT_INFINITY) {
+ /*
+ * Look for an equivalent route that
+ * includes this one before adding
+ * this route.
+ */
+ rt = rtfind(&n->rip_dst);
+ if (rt && equal(from, &rt->rt_router))
+ continue;
+ rtadd(&n->rip_dst, from, n->rip_metric, 0);
+ changes++;
+ }
+ continue;
+ }
+
+ /*
+ * Update if from gateway and different,
+ * shorter, or equivalent but old route
+ * is getting stale.
+ */
+ if (equal(from, &rt->rt_router)) {
+ if (n->rip_metric != rt->rt_metric) {
+ rtchange(rt, from, n->rip_metric);
+ changes++;
+ rt->rt_timer = 0;
+ if (rt->rt_metric >= HOPCNT_INFINITY)
+ rt->rt_timer =
+ GARBAGE_TIME - EXPIRE_TIME;
+ } else if (rt->rt_metric < HOPCNT_INFINITY)
+ rt->rt_timer = 0;
+ } else if ((unsigned) n->rip_metric < rt->rt_metric ||
+ (rt->rt_metric == n->rip_metric &&
+ rt->rt_timer > (EXPIRE_TIME/2) &&
+ (unsigned) n->rip_metric < HOPCNT_INFINITY)) {
+ rtchange(rt, from, n->rip_metric);
+ changes++;
+ rt->rt_timer = 0;
+ }
+ }
+ break;
+ }
+
+ /*
+ * If changes have occurred, and if we have not sent a broadcast
+ * recently, send a dynamic update. This update is sent only
+ * on interfaces other than the one on which we received notice
+ * of the change. If we are within MIN_WAITTIME of a full update,
+ * don't bother sending; if we just sent a dynamic update
+ * and set a timer (nextbcast), delay until that time.
+ * If we just sent a full update, delay the dynamic update.
+ * Set a timer for a randomized value to suppress additional
+ * dynamic updates until it expires; if we delayed sending
+ * the current changes, set needupdate.
+ */
+ if (changes && supplier &&
+ now.tv_sec - lastfullupdate.tv_sec < SUPPLY_INTERVAL-MAX_WAITTIME) {
+ u_long delay;
+ extern long random();
+
+ if (now.tv_sec - lastbcast.tv_sec >= MIN_WAITTIME &&
+ timercmp(&nextbcast, &now, <)) {
+ if (traceactions)
+ fprintf(ftrace, "send dynamic update\n");
+ toall(supply, RTS_CHANGED, ifp);
+ lastbcast = now;
+ needupdate = 0;
+ nextbcast.tv_sec = 0;
+ } else {
+ needupdate++;
+ if (traceactions)
+ fprintf(ftrace, "delay dynamic update\n");
+ }
+#define RANDOMDELAY() (MIN_WAITTIME * 1000000 + \
+ (u_long)random() % ((MAX_WAITTIME - MIN_WAITTIME) * 1000000))
+
+ if (nextbcast.tv_sec == 0) {
+ delay = RANDOMDELAY();
+ if (traceactions)
+ fprintf(ftrace,
+ "inhibit dynamic update for %d usec\n",
+ delay);
+ nextbcast.tv_sec = delay / 1000000;
+ nextbcast.tv_usec = delay % 1000000;
+ timevaladd(&nextbcast, &now);
+ /*
+ * If the next possibly dynamic update
+ * is within MIN_WAITTIME of the next full update,
+ * force the delay past the full update,
+ * or we might send a dynamic update just before
+ * the full update.
+ */
+ if (nextbcast.tv_sec > lastfullupdate.tv_sec +
+ SUPPLY_INTERVAL - MIN_WAITTIME)
+ nextbcast.tv_sec = lastfullupdate.tv_sec +
+ SUPPLY_INTERVAL + 1;
+ }
+ }
+}
diff --git a/usr.sbin/routed/interface.h b/usr.sbin/routed/interface.h
new file mode 100644
index 0000000..fc576d4
--- /dev/null
+++ b/usr.sbin/routed/interface.h
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ * @(#)interface.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * An ``interface'' is similar to an ifnet structure,
+ * except it doesn't contain q'ing info, and it also
+ * handles ``logical'' interfaces (remote gateways
+ * that we want to keep polling even if they go down).
+ * The list of interfaces which we maintain is used
+ * in supplying the gratuitous routing table updates.
+ */
+struct interface {
+ struct interface *int_next;
+ struct sockaddr int_addr; /* address on this host */
+ union {
+ struct sockaddr intu_broadaddr;
+ struct sockaddr intu_dstaddr;
+ } int_intu;
+#define int_broadaddr int_intu.intu_broadaddr /* broadcast address */
+#define int_dstaddr int_intu.intu_dstaddr /* other end of p-to-p link */
+ int int_metric; /* init's routing entry */
+ int int_flags; /* see below */
+ /* START INTERNET SPECIFIC */
+ u_long int_net; /* network # */
+ u_long int_netmask; /* net mask for addr */
+ u_long int_subnet; /* subnet # */
+ u_long int_subnetmask; /* subnet mask for addr */
+ /* END INTERNET SPECIFIC */
+ struct ifdebug int_input, int_output; /* packet tracing stuff */
+ int int_ipackets; /* input packets received */
+ int int_opackets; /* output packets sent */
+ char *int_name; /* from kernel if structure */
+ u_short int_transitions; /* times gone up-down */
+};
+
+/*
+ * 0x1 to 0x10 are reused from the kernel's ifnet definitions,
+ * the others agree with the RTS_ flags defined elsewhere.
+ */
+#define IFF_UP 0x1 /* interface is up */
+#define IFF_BROADCAST 0x2 /* broadcast address valid */
+#define IFF_DEBUG 0x4 /* turn on debugging */
+#define IFF_LOOPBACK 0x8 /* software loopback net */
+#define IFF_POINTOPOINT 0x10 /* interface is point-to-point link */
+
+#define IFF_SUBNET 0x100000 /* interface on subnetted network */
+#define IFF_PASSIVE 0x200000 /* can't tell if up/down */
+#define IFF_INTERFACE 0x400000 /* hardware interface */
+#define IFF_REMOTE 0x800000 /* interface isn't on this machine */
+
+struct interface *if_ifwithaddr();
+struct interface *if_ifwithdstaddr();
+struct interface *if_ifwithnet();
+struct interface *if_iflookup();
diff --git a/usr.sbin/routed/main.c b/usr.sbin/routed/main.c
new file mode 100644
index 0000000..187aca1
--- /dev/null
+++ b/usr.sbin/routed/main.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 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.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/file.h>
+
+#include <net/if.h>
+
+#include <sys/errno.h>
+#include <sys/signal.h>
+#include <sys/syslog.h>
+#include "pathnames.h"
+
+int supplier = -1; /* process should supply updates */
+int gateway = 0; /* 1 if we are a gateway to parts beyond */
+int debug = 0;
+int bufspace = 127*1024; /* max. input buffer size to request */
+
+struct rip *msg = (struct rip *)packet;
+void hup(), rtdeleteall(), sigtrace(), timer();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int n, cc, nfd, omask, tflags = 0;
+ struct sockaddr from;
+ struct timeval *tvp, waittime;
+ struct itimerval itval;
+ register struct rip *query = msg;
+ fd_set ibits;
+ u_char retry;
+
+ argv0 = argv;
+#if BSD >= 43
+ openlog("routed", LOG_PID | LOG_ODELAY, LOG_DAEMON);
+ setlogmask(LOG_UPTO(LOG_WARNING));
+#else
+ openlog("routed", LOG_PID);
+#define LOG_UPTO(x) (x)
+#define setlogmask(x) (x)
+#endif
+ sp = getservbyname("router", "udp");
+ if (sp == NULL) {
+ fprintf(stderr, "routed: router/udp: unknown service\n");
+ exit(1);
+ }
+ addr.sin_family = AF_INET;
+ addr.sin_port = sp->s_port;
+ r = socket(AF_ROUTE, SOCK_RAW, 0);
+ /* later, get smart about lookingforinterfaces */
+ if (r)
+ shutdown(r, 0); /* for now, don't want reponses */
+ else {
+ fprintf(stderr, "routed: no routing socket\n");
+ exit(1);
+ }
+ s = getsocket(AF_INET, SOCK_DGRAM, &addr);
+ if (s < 0)
+ exit(1);
+ argv++, argc--;
+ while (argc > 0 && **argv == '-') {
+ if (strcmp(*argv, "-s") == 0) {
+ supplier = 1;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-q") == 0) {
+ supplier = 0;
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-t") == 0) {
+ tflags++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-d") == 0) {
+ debug++;
+ setlogmask(LOG_UPTO(LOG_DEBUG));
+ argv++, argc--;
+ continue;
+ }
+ if (strcmp(*argv, "-g") == 0) {
+ gateway = 1;
+ argv++, argc--;
+ continue;
+ }
+ fprintf(stderr,
+ "usage: routed [ -s ] [ -q ] [ -t ] [ -g ]\n");
+ exit(1);
+ }
+
+ if (debug == 0 && tflags == 0)
+ daemon(0, 0);
+ /*
+ * Any extra argument is considered
+ * a tracing log file.
+ */
+ if (argc > 0)
+ traceon(*argv);
+ while (tflags-- > 0)
+ bumploglevel();
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ /*
+ * Collect an initial view of the world by
+ * checking the interface configuration and the gateway kludge
+ * file. Then, send a request packet on all
+ * directly connected networks to find out what
+ * everyone else thinks.
+ */
+ rtinit();
+ ifinit();
+ gwkludge();
+ if (gateway > 0)
+ rtdefault();
+ if (supplier < 0)
+ supplier = 0;
+ query->rip_cmd = RIPCMD_REQUEST;
+ query->rip_vers = RIPVERSION;
+ if (sizeof(query->rip_nets[0].rip_dst.sa_family) > 1) /* XXX */
+ query->rip_nets[0].rip_dst.sa_family = htons((u_short)AF_UNSPEC);
+ else
+ query->rip_nets[0].rip_dst.sa_family = AF_UNSPEC;
+ query->rip_nets[0].rip_metric = htonl((u_long)HOPCNT_INFINITY);
+ toall(sndmsg);
+ signal(SIGALRM, timer);
+ signal(SIGHUP, hup);
+ signal(SIGTERM, hup);
+ signal(SIGINT, rtdeleteall);
+ signal(SIGUSR1, sigtrace);
+ signal(SIGUSR2, sigtrace);
+ itval.it_interval.tv_sec = TIMER_RATE;
+ itval.it_value.tv_sec = TIMER_RATE;
+ itval.it_interval.tv_usec = 0;
+ itval.it_value.tv_usec = 0;
+ srandom(getpid());
+ if (setitimer(ITIMER_REAL, &itval, (struct itimerval *)NULL) < 0)
+ syslog(LOG_ERR, "setitimer: %m\n");
+
+ FD_ZERO(&ibits);
+ nfd = s + 1; /* 1 + max(fd's) */
+ for (;;) {
+ FD_SET(s, &ibits);
+ /*
+ * If we need a dynamic update that was held off,
+ * needupdate will be set, and nextbcast is the time
+ * by which we want select to return. Compute time
+ * until dynamic update should be sent, and select only
+ * until then. If we have already passed nextbcast,
+ * just poll.
+ */
+ if (needupdate) {
+ waittime = nextbcast;
+ timevalsub(&waittime, &now);
+ if (waittime.tv_sec < 0) {
+ waittime.tv_sec = 0;
+ waittime.tv_usec = 0;
+ }
+ if (traceactions)
+ fprintf(ftrace,
+ "select until dynamic update %d/%d sec/usec\n",
+ waittime.tv_sec, waittime.tv_usec);
+ tvp = &waittime;
+ } else
+ tvp = (struct timeval *)NULL;
+ n = select(nfd, &ibits, 0, 0, tvp);
+ if (n <= 0) {
+ /*
+ * Need delayed dynamic update if select returned
+ * nothing and we timed out. Otherwise, ignore
+ * errors (e.g. EINTR).
+ */
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ syslog(LOG_ERR, "select: %m");
+ }
+ omask = sigblock(sigmask(SIGALRM));
+ if (n == 0 && needupdate) {
+ if (traceactions)
+ fprintf(ftrace,
+ "send delayed dynamic update\n");
+ (void) gettimeofday(&now,
+ (struct timezone *)NULL);
+ toall(supply, RTS_CHANGED,
+ (struct interface *)NULL);
+ lastbcast = now;
+ needupdate = 0;
+ nextbcast.tv_sec = 0;
+ }
+ sigsetmask(omask);
+ continue;
+ }
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ omask = sigblock(sigmask(SIGALRM));
+#ifdef doesntwork
+/*
+printf("s %d, ibits %x index %d, mod %d, sh %x, or %x &ibits %x\n",
+ s,
+ ibits.fds_bits[0],
+ (s)/(sizeof(fd_mask) * 8),
+ ((s) % (sizeof(fd_mask) * 8)),
+ (1 << ((s) % (sizeof(fd_mask) * 8))),
+ ibits.fds_bits[(s)/(sizeof(fd_mask) * 8)] & (1 << ((s) % (sizeof(fd_mask) * 8))),
+ &ibits
+ );
+*/
+ if (FD_ISSET(s, &ibits))
+#else
+ if (ibits.fds_bits[s/32] & (1 << s))
+#endif
+ process(s);
+ /* handle ICMP redirects */
+ sigsetmask(omask);
+ }
+}
+
+timevaladd(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec += t2->tv_sec;
+ if ((t1->tv_usec += t2->tv_usec) > 1000000) {
+ t1->tv_sec++;
+ t1->tv_usec -= 1000000;
+ }
+}
+
+timevalsub(t1, t2)
+ struct timeval *t1, *t2;
+{
+
+ t1->tv_sec -= t2->tv_sec;
+ if ((t1->tv_usec -= t2->tv_usec) < 0) {
+ t1->tv_sec--;
+ t1->tv_usec += 1000000;
+ }
+}
+
+process(fd)
+ int fd;
+{
+ struct sockaddr from;
+ int fromlen, cc;
+ union {
+ char buf[MAXPACKETSIZE+1];
+ struct rip rip;
+ } inbuf;
+
+ for (;;) {
+ fromlen = sizeof (from);
+ cc = recvfrom(fd, &inbuf, sizeof (inbuf), 0, &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0 && errno != EWOULDBLOCK)
+ perror("recvfrom");
+ break;
+ }
+ if (fromlen != sizeof (struct sockaddr_in))
+ break;
+ rip_input(&from, &inbuf.rip, cc);
+ }
+}
+
+getsocket(domain, type, sin)
+ int domain, type;
+ struct sockaddr_in *sin;
+{
+ int sock, on = 1;
+
+ if ((sock = socket(domain, type, 0)) < 0) {
+ perror("socket");
+ syslog(LOG_ERR, "socket: %m");
+ return (-1);
+ }
+#ifdef SO_BROADCAST
+ if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
+ syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+ close(sock);
+ return (-1);
+ }
+#endif
+#ifdef SO_RCVBUF
+ for (on = bufspace; ; on -= 1024) {
+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
+ &on, sizeof (on)) == 0)
+ break;
+ if (on <= 8*1024) {
+ syslog(LOG_ERR, "setsockopt SO_RCVBUF: %m");
+ break;
+ }
+ }
+ if (traceactions)
+ fprintf(ftrace, "recv buf %d\n", on);
+#endif
+ if (bind(sock, (struct sockaddr *)sin, sizeof (*sin)) < 0) {
+ perror("bind");
+ syslog(LOG_ERR, "bind: %m");
+ close(sock);
+ return (-1);
+ }
+ if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1)
+ syslog(LOG_ERR, "fcntl O_NONBLOCK: %m\n");
+ return (sock);
+}
diff --git a/usr.sbin/routed/output.c b/usr.sbin/routed/output.c
new file mode 100644
index 0000000..528f7fc
--- /dev/null
+++ b/usr.sbin/routed/output.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)output.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+/*
+ * Apply the function "f" to all non-passive
+ * interfaces. If the interface supports the
+ * use of broadcasting use it, otherwise address
+ * the output to the known router.
+ */
+toall(f, rtstate, skipif)
+ int (*f)();
+ int rtstate;
+ struct interface *skipif;
+{
+ register struct interface *ifp;
+ register struct sockaddr *dst;
+ register int flags;
+ extern struct interface *ifnet;
+
+ for (ifp = ifnet; ifp; ifp = ifp->int_next) {
+ if (ifp->int_flags & IFF_PASSIVE || ifp == skipif)
+ continue;
+ dst = ifp->int_flags & IFF_BROADCAST ? &ifp->int_broadaddr :
+ ifp->int_flags & IFF_POINTOPOINT ? &ifp->int_dstaddr :
+ &ifp->int_addr;
+ flags = ifp->int_flags & IFF_INTERFACE ? MSG_DONTROUTE : 0;
+ (*f)(dst, flags, ifp, rtstate);
+ }
+}
+
+/*
+ * Output a preformed packet.
+ */
+/*ARGSUSED*/
+sndmsg(dst, flags, ifp, rtstate)
+ struct sockaddr *dst;
+ int flags;
+ struct interface *ifp;
+ int rtstate;
+{
+
+ (*afswitch[dst->sa_family].af_output)(s, flags,
+ dst, sizeof (struct rip));
+ TRACE_OUTPUT(ifp, dst, sizeof (struct rip));
+}
+
+/*
+ * Supply dst with the contents of the routing tables.
+ * If this won't fit in one packet, chop it up into several.
+ */
+supply(dst, flags, ifp, rtstate)
+ struct sockaddr *dst;
+ int flags;
+ register struct interface *ifp;
+ int rtstate;
+{
+ register struct rt_entry *rt;
+ register struct netinfo *n = msg->rip_nets;
+ register struct rthash *rh;
+ struct rthash *base = hosthash;
+ int doinghost = 1, size;
+ int (*output)() = afswitch[dst->sa_family].af_output;
+ int (*sendroute)() = afswitch[dst->sa_family].af_sendroute;
+ int npackets = 0;
+
+ msg->rip_cmd = RIPCMD_RESPONSE;
+ msg->rip_vers = RIPVERSION;
+ bzero(msg->rip_res1, sizeof(msg->rip_res1));
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++)
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ /*
+ * Don't resend the information on the network
+ * from which it was received (unless sending
+ * in response to a query).
+ */
+ if (ifp && rt->rt_ifp == ifp &&
+ (rt->rt_state & RTS_INTERFACE) == 0)
+ continue;
+ if (rt->rt_state & RTS_EXTERNAL)
+ continue;
+ /*
+ * For dynamic updates, limit update to routes
+ * with the specified state.
+ */
+ if (rtstate && (rt->rt_state & rtstate) == 0)
+ continue;
+ /*
+ * Limit the spread of subnet information
+ * to those who are interested.
+ */
+ if (doinghost == 0 && rt->rt_state & RTS_SUBNET) {
+ if (rt->rt_dst.sa_family != dst->sa_family)
+ continue;
+ if ((*sendroute)(rt, dst) == 0)
+ continue;
+ }
+ size = (char *)n - packet;
+ if (size > MAXPACKETSIZE - sizeof (struct netinfo)) {
+ TRACE_OUTPUT(ifp, dst, size);
+ (*output)(s, flags, dst, size);
+ /*
+ * If only sending to ourselves,
+ * one packet is enough to monitor interface.
+ */
+ if (ifp && (ifp->int_flags &
+ (IFF_BROADCAST | IFF_POINTOPOINT | IFF_REMOTE)) == 0)
+ return;
+ n = msg->rip_nets;
+ npackets++;
+ }
+ n->rip_dst = rt->rt_dst;
+#if BSD < 198810
+ if (sizeof(n->rip_dst.sa_family) > 1) /* XXX */
+ n->rip_dst.sa_family = htons(n->rip_dst.sa_family);
+#else
+#define osa(x) ((struct osockaddr *)(&(x)))
+ osa(n->rip_dst)->sa_family = htons(n->rip_dst.sa_family);
+#endif
+ n->rip_metric = htonl(rt->rt_metric);
+ n++;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (n != msg->rip_nets || (npackets == 0 && rtstate == 0)) {
+ size = (char *)n - packet;
+ TRACE_OUTPUT(ifp, dst, size);
+ (*output)(s, flags, dst, size);
+ }
+}
diff --git a/usr.sbin/routed/pathnames.h b/usr.sbin/routed/pathnames.h
new file mode 100644
index 0000000..461d82b
--- /dev/null
+++ b/usr.sbin/routed/pathnames.h
@@ -0,0 +1,38 @@
+/*
+ * 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/5/93
+ */
+
+#include <paths.h>
+
+#define _PATH_GATEWAYS "/etc/gateways"
diff --git a/usr.sbin/routed/query/Makefile b/usr.sbin/routed/query/Makefile
new file mode 100644
index 0000000..0e7d1cd
--- /dev/null
+++ b/usr.sbin/routed/query/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= query
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/query/query.c b/usr.sbin/routed/query/query.c
new file mode 100644
index 0000000..a800388
--- /dev/null
+++ b/usr.sbin/routed/query/query.c
@@ -0,0 +1,294 @@
+/*-
+ * Copyright (c) 1982, 1986, 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) 1982, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)query.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define WTIME 5 /* Time to wait for all responses */
+#define STIME 500000 /* usec to wait for another response */
+
+int s;
+int timedout;
+void timeout();
+char packet[MAXPACKETSIZE];
+int nflag;
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, cc, count, bits;
+ struct sockaddr from;
+ struct sigaction sigact;
+ int fromlen = sizeof(from), size = 32*1024;
+ struct timeval shorttime;
+
+ while ((ch = getopt(argc, argv, "n")) != EOF)
+ switch (ch) {
+ case 'n':
+ nflag++;
+ break;
+ case '?':
+ default:
+ goto usage;
+ }
+ argv += optind;
+
+ if (!*argv) {
+usage: printf("usage: query [-n] hosts...\n");
+ exit(1);
+ }
+
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ if (setsockopt(s, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)) < 0)
+ perror("setsockopt SO_RCVBUF");
+
+ while (*argv) {
+ query(*argv++);
+ count++;
+ }
+
+ /*
+ * Listen for returning packets;
+ * may be more than one packet per host.
+ */
+ bits = 1 << s;
+ bzero(&shorttime, sizeof(shorttime));
+ shorttime.tv_usec = STIME;
+ bzero(&sigact, sizeof(sigact));
+ sigact.sa_handler = timeout;
+ /*sigact.sa_flags = 0; /* no restart */
+ if (sigaction(SIGALRM, &sigact, (struct sigaction *)NULL) == -1)
+ perror("sigaction");
+ alarm(WTIME);
+ while ((count > 0 && !timedout) ||
+ select(20, (fd_set *)&bits, NULL, NULL, &shorttime) > 0) {
+ cc = recvfrom(s, packet, sizeof (packet), 0,
+ &from, &fromlen);
+ if (cc <= 0) {
+ if (cc < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("recvfrom");
+ (void) close(s);
+ exit(1);
+ }
+ continue;
+ }
+ rip_input(&from, cc);
+ count--;
+ }
+ exit (count > 0 ? count : 0);
+}
+
+query(host)
+ char *host;
+{
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(host);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(host);
+ if (hp == NULL) {
+ fprintf(stderr, "query: %s: ", host);
+ herror((char *)NULL);
+ exit(1);
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ msg->rip_cmd = RIPCMD_REQUEST;
+ msg->rip_vers = RIPVERSION;
+ msg->rip_nets[0].rip_dst.sa_family = htons(AF_UNSPEC);
+ msg->rip_nets[0].rip_metric = htonl(HOPCNT_INFINITY);
+ if (sendto(s, packet, sizeof (struct rip), 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(host);
+}
+
+/*
+ * Handle an incoming routing packet.
+ */
+rip_input(from, size)
+ struct sockaddr_in *from;
+ int size;
+{
+ register struct rip *msg = (struct rip *)packet;
+ register struct netinfo *n;
+ char *name;
+ int lna, net, subnet;
+ struct hostent *hp;
+ struct netent *np;
+
+ if (msg->rip_cmd != RIPCMD_RESPONSE)
+ return;
+ printf("%d bytes from ", size);
+ if (nflag)
+ printf("%s:\n", inet_ntoa(from->sin_addr));
+ else {
+ hp = gethostbyaddr((char *)&from->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ name = hp == 0 ? "???" : hp->h_name;
+ printf("%s(%s):\n", name, inet_ntoa(from->sin_addr));
+ }
+ size -= sizeof (int);
+ n = msg->rip_nets;
+ while (size > 0) {
+ if (size < sizeof (struct netinfo))
+ break;
+ if (msg->rip_vers > 0) {
+ n->rip_dst.sa_family =
+ ntohs(n->rip_dst.sa_family);
+ n->rip_metric = ntohl(n->rip_metric);
+ }
+ switch (n->rip_dst.sa_family) {
+
+ case AF_INET:
+ { register struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)&n->rip_dst;
+ net = inet_netof(sin->sin_addr);
+ subnet = inet_subnetof(sin->sin_addr);
+ lna = inet_lnaof(sin->sin_addr);
+ name = "???";
+ if (!nflag) {
+ if (sin->sin_addr.s_addr == 0)
+ name = "default";
+ else if (lna == INADDR_ANY) {
+ np = getnetbyaddr(net, AF_INET);
+ if (np)
+ name = np->n_name;
+ else if (net == 0)
+ name = "default";
+ } else if ((lna & 0xff) == 0 &&
+ (np = getnetbyaddr(subnet, AF_INET))) {
+ struct in_addr subnaddr, inet_makeaddr();
+
+ subnaddr = inet_makeaddr(subnet, INADDR_ANY);
+ if (bcmp(&sin->sin_addr, &subnaddr,
+ sizeof(subnaddr)) == 0)
+ name = np->n_name;
+ else
+ goto host;
+ } else {
+ host:
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof (struct in_addr), AF_INET);
+ if (hp)
+ name = hp->h_name;
+ }
+ printf("\t%-17s metric %2d name %s\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric, name);
+ } else
+ printf("\t%-17s metric %2d\n",
+ inet_ntoa(sin->sin_addr), n->rip_metric);
+ break;
+ }
+
+ default:
+ { u_short *p = (u_short *)n->rip_dst.sa_data;
+
+ printf("\t(af %d) %x %x %x %x %x %x %x, metric %d\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6],
+ n->rip_dst.sa_family,
+ n->rip_metric);
+ break;
+ }
+
+ }
+ size -= sizeof (struct netinfo), n++;
+ }
+}
+
+void
+timeout()
+{
+ timedout = 1;
+}
+
+/*
+ * Return the possible subnetwork number from an internet address.
+ * SHOULD FIND OUT WHETHER THIS IS A LOCAL NETWORK BEFORE LOOKING
+ * INSIDE OF THE HOST PART. We can only believe this if we have other
+ * information (e.g., we can find a name for this number).
+ */
+inet_subnetof(in)
+ struct in_addr in;
+{
+ register u_long i = ntohl(in.s_addr);
+
+ if (IN_CLASSA(i))
+ return ((i & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
+ else if (IN_CLASSB(i))
+ return ((i & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
+ else
+ return ((i & 0xffffffc0) >> 28);
+}
diff --git a/usr.sbin/routed/routed.8 b/usr.sbin/routed/routed.8
new file mode 100644
index 0000000..8d9ea20
--- /dev/null
+++ b/usr.sbin/routed/routed.8
@@ -0,0 +1,358 @@
+.\" 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.
+.\"
+.\" @(#)routed.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.Dt ROUTED 8
+.Os BSD 4.2
+.Sh NAME
+.Nm routed
+.Nd network routing daemon
+.Sh SYNOPSIS
+.Nm routed
+.Op Fl d
+.Op Fl g
+.Op Fl q
+.Op Fl s
+.Op Fl t
+.Op Ar logfile
+.Sh DESCRIPTION
+.Nm Routed
+is invoked at boot time to manage the network routing tables.
+The routing daemon uses a variant of the Xerox NS Routing
+Information Protocol in maintaining up to date kernel routing
+table entries.
+It used a generalized protocol capable of use with multiple
+address types, but is currently used only for Internet routing
+within a cluster of networks.
+.Pp
+In normal operation
+.Nm routed
+listens on the
+.Xr udp 4
+socket for the
+.Xr route 8
+service (see
+.Xr services 5 )
+for routing information packets. If the host is an
+internetwork router, it periodically supplies copies
+of its routing tables to any directly connected hosts
+and networks.
+.Pp
+When
+.Nm routed
+is started, it uses the
+.Dv SIOCGIFCONF
+.Xr ioctl 2
+to find those
+directly connected interfaces configured into the
+system and marked ``up'' (the software loopback interface
+is ignored). If multiple interfaces
+are present, it is assumed that the host will forward packets
+between networks.
+.Nm Routed
+then transmits a
+.Em request
+packet on each interface (using a broadcast packet if
+the interface supports it) and enters a loop, listening
+for
+.Em request
+and
+.Em response
+packets from other hosts.
+.Pp
+When a
+.Em request
+packet is received,
+.Nm routed
+formulates a reply based on the information maintained in its
+internal tables. The
+.Em response
+packet generated contains a list of known routes, each marked
+with a ``hop count'' metric (a count of 16, or greater, is
+considered ``infinite''). The metric associated with each
+route returned provides a metric
+.Em relative to the sender .
+.Pp
+.Em Response
+packets received by
+.Nm routed
+are used to update the routing tables if one of the following
+conditions is satisfied:
+.Bl -enum
+.It
+No routing table entry exists for the destination network
+or host, and the metric indicates the destination is ``reachable''
+(i.e. the hop count is not infinite).
+.It
+The source host of the packet is the same as the router in the
+existing routing table entry. That is, updated information is
+being received from the very internetwork router through which
+packets for the destination are being routed.
+.It
+The existing entry in the routing table has not been updated for
+some time (defined to be 90 seconds) and the route is at least
+as cost effective as the current route.
+.It
+The new route describes a shorter route to the destination than
+the one currently stored in the routing tables; the metric of
+the new route is compared against the one stored in the table
+to decide this.
+.El
+.Pp
+When an update is applied,
+.Nm routed
+records the change in its internal tables and updates the kernel
+routing table.
+The change is reflected in the next
+.Em response
+packet sent.
+.Pp
+In addition to processing incoming packets,
+.Nm routed
+also periodically checks the routing table entries.
+If an entry has not been updated for 3 minutes, the entry's metric
+is set to infinity and marked for deletion. Deletions are delayed
+an additional 60 seconds to insure the invalidation is propagated
+throughout the local internet.
+.Pp
+Hosts acting as internetwork routers gratuitously supply their
+routing tables every 30 seconds to all directly connected hosts
+and networks.
+The response is sent to the broadcast address on nets capable of that function,
+to the destination address on point-to-point links, and to the router's
+own address on other networks.
+The normal routing tables are bypassed when sending gratuitous responses.
+The reception of responses on each network is used to determine that the
+network and interface are functioning correctly.
+If no response is received on an interface, another route may be chosen
+to route around the interface, or the route may be dropped if no alternative
+is available.
+.Pp
+Options supported by
+.Nm routed :
+.Bl -tag -width Ds
+.It Fl d
+Enable additional debugging information to be logged,
+such as bad packets received.
+.It Fl g
+This flag is used on internetwork routers to offer a route
+to the ``default'' destination.
+This is typically used on a gateway to the Internet,
+or on a gateway that uses another routing protocol whose routes
+are not reported to other local routers.
+.It Fl s
+Supplying this
+option forces
+.Nm routed
+to supply routing information whether it is acting as an internetwork
+router or not.
+This is the default if multiple network interfaces are present,
+or if a point-to-point link is in use.
+.It Fl q
+This
+is the opposite of the
+.Fl s
+option.
+.It Fl t
+If the
+.Fl t
+option is specified, all packets sent or received are
+printed on the standard output. In addition,
+.Nm routed
+will not divorce itself from the controlling terminal
+so that interrupts from the keyboard will kill the process.
+.El
+.Pp
+Any other argument supplied is interpreted as the name
+of file in which
+.Nm routed Ns \'s
+actions should be logged. This log contains information
+about any changes to the routing tables and, if not tracing all packets,
+a history of recent messages sent and received which are related to
+the changed route.
+.Pp
+In addition to the facilities described above,
+.Nm routed
+supports the notion of ``distant''
+.Em passive
+and
+.Em active
+gateways. When
+.Nm routed
+is started up, it reads the file
+.Pa /etc/gateways
+to find gateways which may not be located using
+only information from the
+.Dv SIOGIFCONF
+.Xr ioctl 2 .
+Gateways specified in this manner should be marked passive
+if they are not expected to exchange routing information,
+while gateways marked active
+should be willing to exchange routing information (i.e.
+they should have a
+.Nm routed
+process running on the machine).
+Routes through passive gateways are installed in the
+kernel's routing tables once upon startup.
+Such routes are not included in
+any routing information transmitted.
+Active gateways are treated equally to network
+interfaces. Routing information is distributed
+to the gateway and if no routing information is
+received for a period of time, the associated
+route is deleted.
+Gateways marked
+.Em external
+are also passive, but are not placed in the kernel
+routing table nor are they included in routing updates.
+The function of external entries is to inform
+.Nm routed
+that another routing process
+will install such a route, and that alternate routes to that destination
+should not be installed.
+Such entries are only required when both routers may learn of routes
+to the same destination.
+.Pp
+The
+.Pa /etc/gateways
+is comprised of a series of lines, each in
+the following format:
+.Bd -ragged
+.Pf < Cm net No \&|
+.Cm host Ns >
+.Ar name1
+.Cm gateway
+.Ar name2
+.Cm metric
+.Ar value
+.Pf < Cm passive No \&|
+.Cm active No \&|
+.Cm external Ns >
+.Ed
+.Pp
+The
+.Cm net
+or
+.Cm host
+keyword indicates if the route is to a network or specific host.
+.Pp
+.Ar Name1
+is the name of the destination network or host. This may be a
+symbolic name located in
+.Pa /etc/networks
+or
+.Pa /etc/hosts
+(or, if started after
+.Xr named 8 ,
+known to the name server),
+or an Internet address specified in ``dot'' notation; see
+.Xr inet 3 .
+.Pp
+.Ar Name2
+is the name or address of the gateway to which messages should
+be forwarded.
+.Pp
+.Ar Value
+is a metric indicating the hop count to the destination host
+or network.
+.Pp
+One of the keywords
+.Cm passive ,
+.Cm active
+or
+.Cm external
+indicates if the gateway should be treated as
+.Em passive
+or
+.Em active
+(as described above),
+or whether the gateway is
+.Em external
+to the scope of the
+.Nm routed
+protocol.
+.Pp
+Internetwork routers that are directly attached to the Arpanet or Milnet
+should use the Exterior Gateway Protocol
+.Pq Tn EGP
+to gather routing information
+rather then using a static routing table of passive gateways.
+.Tn EGP
+is required in order to provide routes for local networks to the rest
+of the Internet system.
+.Sh FILES
+.Bl -tag -width /etc/gateways -compact
+.It Pa /etc/gateways
+for distant gateways
+.El
+.Sh SEE ALSO
+.Xr udp 4 ,
+.Xr icmp 4 ,
+.Xr XNSrouted 8 ,
+.Xr htable 8
+.Rs
+.%T Internet Transport Protocols
+.%R XSIS 028112
+.%Q Xerox System Integration Standard
+.Re
+.Sh BUGS
+The kernel's routing tables may not correspond to those of
+.Nm routed
+when redirects change or add routes.
+.Nm Routed
+should note any redirects received by reading
+the
+.Tn ICMP
+packets received via a raw socket.
+.Pp
+.Nm Routed
+should incorporate other routing protocols,
+such as Xerox
+.Tn \&NS
+.Pq Xr XNSrouted 8
+and
+.Tn EGP .
+Using separate processes for each requires configuration options
+to avoid redundant or competing routes.
+.Pp
+.Nm Routed
+should listen to intelligent interfaces, such as an
+.Tn IMP ,
+to gather more information.
+It does not always detect unidirectional failures in network interfaces
+(e.g., when the output side fails).
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/usr.sbin/routed/startup.c b/usr.sbin/routed/startup.c
new file mode 100644
index 0000000..e87d9e9
--- /dev/null
+++ b/usr.sbin/routed/startup.c
@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)startup.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+struct interface *ifnet;
+struct interface **ifnext = &ifnet;
+int lookforinterfaces = 1;
+int externalinterfaces = 0; /* # of remote and local interfaces */
+int foundloopback; /* valid flag for loopaddr */
+struct sockaddr loopaddr; /* our address on loopback */
+
+
+void
+quit(s)
+ char *s;
+{
+ extern int errno;
+ int sverrno = errno;
+
+ (void) fprintf(stderr, "route: ");
+ if (s)
+ (void) fprintf(stderr, "%s: ", s);
+ (void) fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(1);
+ /* NOTREACHED */
+}
+
+struct rt_addrinfo info;
+/* Sleazy use of local variables throughout file, warning!!!! */
+#define netmask info.rti_info[RTAX_NETMASK]
+#define ifaaddr info.rti_info[RTAX_IFA]
+#define brdaddr info.rti_info[RTAX_BRD]
+
+#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;
+
+ bzero(rtinfo->rti_info, 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);
+ }
+}
+
+/*
+ * Find the network interfaces which have configured themselves.
+ * If the interface is present but not yet up (for example an
+ * ARPANET IMP), set the lookforinterfaces flag so we'll
+ * come back later and look again.
+ */
+ifinit()
+{
+ struct interface ifs, *ifp;
+ size_t needed;
+ int mib[6], no_ipaddr = 0, flags = 0;
+ char *buf, *cplim, *cp;
+ register struct if_msghdr *ifm;
+ register struct ifa_msghdr *ifam;
+ struct sockaddr_dl *sdl;
+ struct sockaddr_in *sin;
+ u_long i;
+
+ 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");
+ lookforinterfaces = 0;
+ cplim = buf + needed;
+ for (cp = buf; cp < cplim; cp += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)cp;
+ if (ifm->ifm_type == RTM_IFINFO) {
+ bzero(&ifs, sizeof(ifs));
+ ifs.int_flags = flags = (0xffff & ifm->ifm_flags) | IFF_INTERFACE;
+ if ((flags & IFF_UP) == 0 || no_ipaddr)
+ lookforinterfaces = 1;
+ sdl = (struct sockaddr_dl *) (ifm + 1);
+ sdl->sdl_data[sdl->sdl_nlen] = 0;
+ no_ipaddr = 1;
+ continue;
+ }
+ if (ifm->ifm_type != RTM_NEWADDR)
+ quit("ifinit: out of sync");
+ if ((flags & IFF_UP) == 0)
+ continue;
+ ifam = (struct ifa_msghdr *)ifm;
+ info.rti_addrs = ifam->ifam_addrs;
+ rt_xaddrs((char *)(ifam + 1), cp + ifam->ifam_msglen, &info);
+ if (ifaaddr == 0) {
+ syslog(LOG_ERR, "%s: (get addr)", sdl->sdl_data);
+ continue;
+ }
+ ifs.int_addr = *ifaaddr;
+ if (ifs.int_addr.sa_family != AF_INET)
+ continue;
+ no_ipaddr = 0;
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get dstaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ if (brdaddr->sa_family == AF_UNSPEC) {
+ lookforinterfaces = 1;
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * already known to us?
+ * This allows multiple point-to-point links
+ * to share a source address (possibly with one
+ * other link), but assumes that there will not be
+ * multiple links with the same destination address.
+ */
+ if (ifs.int_flags & IFF_POINTOPOINT) {
+ if (if_ifwithdstaddr(&ifs.int_dstaddr))
+ continue;
+ } else if (if_ifwithaddr(&ifs.int_addr))
+ continue;
+ if (ifs.int_flags & IFF_LOOPBACK) {
+ ifs.int_flags |= IFF_PASSIVE;
+ foundloopback = 1;
+ loopaddr = ifs.int_addr;
+ for (ifp = ifnet; ifp; ifp = ifp->int_next)
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ add_ptopt_localrt(ifp);
+ }
+ if (ifs.int_flags & IFF_BROADCAST) {
+ if (brdaddr == 0) {
+ syslog(LOG_ERR, "%s: (get broadaddr)",
+ sdl->sdl_data);
+ continue;
+ }
+ ifs.int_dstaddr = *brdaddr;
+ }
+ /*
+ * Use a minimum metric of one;
+ * treat the interface metric (default 0)
+ * as an increment to the hop count of one.
+ */
+ ifs.int_metric = ifam->ifam_metric + 1;
+ if (netmask == 0) {
+ syslog(LOG_ERR, "%s: (get netmask)",
+ sdl->sdl_data);
+ continue;
+ }
+ sin = (struct sockaddr_in *)netmask;
+ ifs.int_subnetmask = ntohl(sin->sin_addr.s_addr);
+ sin = (struct sockaddr_in *)&ifs.int_addr;
+ i = ntohl(sin->sin_addr.s_addr);
+ if (IN_CLASSA(i))
+ ifs.int_netmask = IN_CLASSA_NET;
+ else if (IN_CLASSB(i))
+ ifs.int_netmask = IN_CLASSB_NET;
+ else
+ ifs.int_netmask = IN_CLASSC_NET;
+ ifs.int_net = i & ifs.int_netmask;
+ ifs.int_subnet = i & ifs.int_subnetmask;
+ if (ifs.int_subnetmask != ifs.int_netmask)
+ ifs.int_flags |= IFF_SUBNET;
+ ifp = (struct interface *)
+ malloc(sdl->sdl_nlen + 1 + sizeof(ifs));
+ if (ifp == 0) {
+ printf("routed: out of memory\n");
+ lookforinterfaces = 1;
+ break;
+ }
+ *ifp = ifs;
+ /*
+ * Count the # of directly connected networks
+ * and point to point links which aren't looped
+ * back to ourself. This is used below to
+ * decide if we should be a routing ``supplier''.
+ */
+ if ((ifs.int_flags & IFF_LOOPBACK) == 0 &&
+ ((ifs.int_flags & IFF_POINTOPOINT) == 0 ||
+ if_ifwithaddr(&ifs.int_dstaddr) == 0))
+ externalinterfaces++;
+ /*
+ * If we have a point-to-point link, we want to act
+ * as a supplier even if it's our only interface,
+ * as that's the only way our peer on the other end
+ * can tell that the link is up.
+ */
+ if ((ifs.int_flags & IFF_POINTOPOINT) && supplier < 0)
+ supplier = 1;
+ ifp->int_name = (char *)(ifp + 1);
+ strcpy(ifp->int_name, sdl->sdl_data);
+ *ifnext = ifp;
+ ifnext = &ifp->int_next;
+ traceinit(ifp);
+ addrouteforif(ifp);
+ }
+ if (externalinterfaces > 1 && supplier < 0)
+ supplier = 1;
+ free(buf);
+}
+
+/*
+ * Add route for interface if not currently installed.
+ * Create route to other end if a point-to-point link,
+ * otherwise a route to this (sub)network.
+ * INTERNET SPECIFIC.
+ */
+addrouteforif(ifp)
+ register struct interface *ifp;
+{
+ struct sockaddr_in net;
+ struct sockaddr *dst;
+ int state;
+ register struct rt_entry *rt;
+
+ if (ifp->int_flags & IFF_POINTOPOINT)
+ dst = &ifp->int_dstaddr;
+ else {
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_subnet, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ }
+ rt = rtfind(dst);
+ if (rt &&
+ (rt->rt_state & (RTS_INTERFACE | RTS_INTERNAL)) == RTS_INTERFACE)
+ return;
+ if (rt)
+ rtdelete(rt);
+ /*
+ * If interface on subnetted network,
+ * install route to network as well.
+ * This is meant for external viewers.
+ */
+ if ((ifp->int_flags & (IFF_SUBNET|IFF_POINTOPOINT)) == IFF_SUBNET) {
+ struct in_addr subnet;
+
+ subnet = net.sin_addr;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ rt = rtfind(dst);
+ if (rt == 0)
+ rtadd(dst, &ifp->int_addr, ifp->int_metric,
+ ((ifp->int_flags & (IFF_INTERFACE|IFF_REMOTE)) |
+ RTS_PASSIVE | RTS_INTERNAL | RTS_SUBNET));
+ else if ((rt->rt_state & (RTS_INTERNAL|RTS_SUBNET)) ==
+ (RTS_INTERNAL|RTS_SUBNET) &&
+ ifp->int_metric < rt->rt_metric)
+ rtchange(rt, &rt->rt_router, ifp->int_metric);
+ net.sin_addr = subnet;
+ }
+ if (ifp->int_transitions++ > 0)
+ syslog(LOG_ERR, "re-installing interface %s", ifp->int_name);
+ state = ifp->int_flags &
+ (IFF_INTERFACE | IFF_PASSIVE | IFF_REMOTE | IFF_SUBNET);
+ if (ifp->int_flags & IFF_POINTOPOINT &&
+ (ntohl(((struct sockaddr_in *)&ifp->int_dstaddr)->sin_addr.s_addr) &
+ ifp->int_netmask) != ifp->int_net)
+ state &= ~RTS_SUBNET;
+ if (ifp->int_flags & IFF_LOOPBACK)
+ state |= RTS_EXTERNAL;
+ rtadd(dst, &ifp->int_addr, ifp->int_metric, state);
+ if (ifp->int_flags & IFF_POINTOPOINT && foundloopback)
+ add_ptopt_localrt(ifp);
+}
+
+/*
+ * Add route to local end of point-to-point using loopback.
+ * If a route to this network is being sent to neighbors on other nets,
+ * mark this route as subnet so we don't have to propagate it too.
+ */
+add_ptopt_localrt(ifp)
+ register struct interface *ifp;
+{
+ struct rt_entry *rt;
+ struct sockaddr *dst;
+ struct sockaddr_in net;
+ int state;
+
+ state = RTS_INTERFACE | RTS_PASSIVE;
+
+ /* look for route to logical network */
+ bzero((char *)&net, sizeof (net));
+ net.sin_family = AF_INET;
+ net.sin_addr = inet_makeaddr(ifp->int_net, INADDR_ANY);
+ dst = (struct sockaddr *)&net;
+ rt = rtfind(dst);
+ if (rt && rt->rt_state & RTS_INTERNAL)
+ state |= RTS_SUBNET;
+
+ dst = &ifp->int_addr;
+ if (rt = rtfind(dst)) {
+ if (rt && rt->rt_state & RTS_INTERFACE)
+ return;
+ rtdelete(rt);
+ }
+ rtadd(dst, &loopaddr, 1, state);
+}
+
+/*
+ * As a concession to the ARPANET we read a list of gateways
+ * from /etc/gateways and add them to our tables. This file
+ * exists at each ARPANET gateway and indicates a set of ``remote''
+ * gateways (i.e. a gateway which we can't immediately determine
+ * if it's present or not as we can do for those directly connected
+ * at the hardware level). If a gateway is marked ``passive''
+ * in the file, then we assume it doesn't have a routing process
+ * of our design and simply assume it's always present. Those
+ * not marked passive are treated as if they were directly
+ * connected -- they're added into the interface list so we'll
+ * send them routing updates.
+ *
+ * PASSIVE ENTRIES AREN'T NEEDED OR USED ON GATEWAYS RUNNING EGP.
+ */
+gwkludge()
+{
+ struct sockaddr_in dst, gate;
+ FILE *fp;
+ char *type, *dname, *gname, *qual, buf[BUFSIZ];
+ struct interface *ifp;
+ int metric, n;
+ struct rt_entry route;
+
+ fp = fopen(_PATH_GATEWAYS, "r");
+ if (fp == NULL)
+ return;
+ qual = buf;
+ dname = buf + 64;
+ gname = buf + ((BUFSIZ - 64) / 3);
+ type = buf + (((BUFSIZ - 64) * 2) / 3);
+ bzero((char *)&dst, sizeof (dst));
+ bzero((char *)&gate, sizeof (gate));
+ bzero((char *)&route, sizeof(route));
+/* format: {net | host} XX gateway XX metric DD [passive | external]\n */
+#define readentry(fp) \
+ fscanf((fp), "%s %s gateway %s metric %d %s\n", \
+ type, dname, gname, &metric, qual)
+ for (;;) {
+ if ((n = readentry(fp)) == EOF)
+ break;
+ if (!getnetorhostname(type, dname, &dst))
+ continue;
+ if (!gethostnameornumber(gname, &gate))
+ continue;
+ if (metric == 0) /* XXX */
+ metric = 1;
+ if (strcmp(qual, "passive") == 0) {
+ /*
+ * Passive entries aren't placed in our tables,
+ * only the kernel's, so we don't copy all of the
+ * external routing information within a net.
+ * Internal machines should use the default
+ * route to a suitable gateway (like us).
+ */
+ route.rt_dst = *(struct sockaddr *) &dst;
+ route.rt_router = *(struct sockaddr *) &gate;
+ route.rt_flags = RTF_UP;
+ if (strcmp(type, "host") == 0)
+ route.rt_flags |= RTF_HOST;
+ if (metric)
+ route.rt_flags |= RTF_GATEWAY;
+ (void) rtioctl(ADD, &route.rt_rt);
+ continue;
+ }
+ if (strcmp(qual, "external") == 0) {
+ /*
+ * Entries marked external are handled
+ * by other means, e.g. EGP,
+ * and are placed in our tables only
+ * to prevent overriding them
+ * with something else.
+ */
+ rtadd(&dst, &gate, metric, RTS_EXTERNAL|RTS_PASSIVE);
+ continue;
+ }
+ /* assume no duplicate entries */
+ externalinterfaces++;
+ ifp = (struct interface *)malloc(sizeof (*ifp));
+ bzero((char *)ifp, sizeof (*ifp));
+ ifp->int_flags = IFF_REMOTE;
+ /* can't identify broadcast capability */
+ ifp->int_net = inet_netof(dst.sin_addr);
+ if (strcmp(type, "host") == 0) {
+ ifp->int_flags |= IFF_POINTOPOINT;
+ ifp->int_dstaddr = *((struct sockaddr *)&dst);
+ }
+ ifp->int_addr = *((struct sockaddr *)&gate);
+ ifp->int_metric = metric;
+ ifp->int_next = ifnet;
+ ifnet = ifp;
+ addrouteforif(ifp);
+ }
+ fclose(fp);
+}
+
+getnetorhostname(type, name, sin)
+ char *type, *name;
+ struct sockaddr_in *sin;
+{
+
+ if (strcmp(type, "net") == 0) {
+ struct netent *np = getnetbyname(name);
+ int n;
+
+ if (np == 0)
+ n = inet_network(name);
+ else {
+ if (np->n_addrtype != AF_INET)
+ return (0);
+ n = np->n_net;
+ /*
+ * getnetbyname returns right-adjusted value.
+ */
+ if (n < 128)
+ n <<= IN_CLASSA_NSHIFT;
+ else if (n < 65536)
+ n <<= IN_CLASSB_NSHIFT;
+ else
+ n <<= IN_CLASSC_NSHIFT;
+ }
+ sin->sin_family = AF_INET;
+ sin->sin_addr = inet_makeaddr(n, INADDR_ANY);
+ return (1);
+ }
+ if (strcmp(type, "host") == 0) {
+ struct hostent *hp = gethostbyname(name);
+
+ if (hp == 0)
+ sin->sin_addr.s_addr = inet_addr(name);
+ else {
+ if (hp->h_addrtype != AF_INET)
+ return (0);
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ }
+ sin->sin_family = AF_INET;
+ return (1);
+ }
+ return (0);
+}
+
+gethostnameornumber(name, sin)
+ char *name;
+ struct sockaddr_in *sin;
+{
+ struct hostent *hp;
+
+ hp = gethostbyname(name);
+ if (hp) {
+ bcopy(hp->h_addr, &sin->sin_addr, hp->h_length);
+ sin->sin_family = hp->h_addrtype;
+ return (1);
+ }
+ sin->sin_addr.s_addr = inet_addr(name);
+ sin->sin_family = AF_INET;
+ return (sin->sin_addr.s_addr != -1);
+}
diff --git a/usr.sbin/routed/table.h b/usr.sbin/routed/table.h
new file mode 100644
index 0000000..01336f0
--- /dev/null
+++ b/usr.sbin/routed/table.h
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ *
+ * @(#)table.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Routing table structure; differs a bit from kernel tables.
+ *
+ * Note: the union below must agree in the first 4 members
+ * so the ioctl's will work.
+ */
+struct rthash {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+};
+#ifdef RTM_ADD
+#define rtentry ortentry
+#endif
+
+struct rt_entry {
+ struct rt_entry *rt_forw;
+ struct rt_entry *rt_back;
+ union {
+ struct rtentry rtu_rt;
+ struct rtuentry {
+ u_long rtu_hash;
+ struct sockaddr rtu_dst;
+ struct sockaddr rtu_router;
+ short rtu_rtflags; /* used by rtioctl */
+ short rtu_wasted[5];
+ int rtu_flags;
+ int rtu_state;
+ int rtu_timer;
+ int rtu_metric;
+ int rtu_ifmetric;
+ struct interface *rtu_ifp;
+ } rtu_entry;
+ } rt_rtu;
+};
+
+#define rt_rt rt_rtu.rtu_entry /* pass to ioctl */
+#define rt_hash rt_rtu.rtu_entry.rtu_hash /* for net or host */
+#define rt_dst rt_rtu.rtu_entry.rtu_dst /* match value */
+#define rt_router rt_rtu.rtu_entry.rtu_router /* who to forward to */
+#define rt_flags rt_rtu.rtu_entry.rtu_flags /* kernel flags */
+#define rt_timer rt_rtu.rtu_entry.rtu_timer /* for invalidation */
+#define rt_state rt_rtu.rtu_entry.rtu_state /* see below */
+#define rt_metric rt_rtu.rtu_entry.rtu_metric /* cost of route */
+#define rt_ifmetric rt_rtu.rtu_entry.rtu_ifmetric /* cost of route if */
+#define rt_ifp rt_rtu.rtu_entry.rtu_ifp /* interface to take */
+
+#define ROUTEHASHSIZ 32 /* must be a power of 2 */
+#define ROUTEHASHMASK (ROUTEHASHSIZ - 1)
+
+/*
+ * "State" of routing table entry.
+ */
+#define RTS_CHANGED 0x1 /* route has been altered recently */
+#define RTS_EXTERNAL 0x2 /* extern info, not installed or sent */
+#define RTS_INTERNAL 0x4 /* internal route, not installed */
+#define RTS_PASSIVE IFF_PASSIVE /* don't time out route */
+#define RTS_INTERFACE IFF_INTERFACE /* route is for network interface */
+#define RTS_REMOTE IFF_REMOTE /* route is for ``remote'' entity */
+#define RTS_SUBNET IFF_SUBNET /* route is for network subnet */
+
+/*
+ * Flags are same as kernel, with this addition for af_rtflags:
+ */
+#define RTF_SUBNET 0x80000 /* pseudo: route to subnet */
+
+struct rthash nethash[ROUTEHASHSIZ];
+struct rthash hosthash[ROUTEHASHSIZ];
+struct rt_entry *rtlookup();
+struct rt_entry *rtfind();
diff --git a/usr.sbin/routed/tables.c b/usr.sbin/routed/tables.c
new file mode 100644
index 0000000..ac837f8
--- /dev/null
+++ b/usr.sbin/routed/tables.c
@@ -0,0 +1,428 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)tables.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/syslog.h>
+
+#ifndef DEBUG
+#define DEBUG 0
+#endif
+
+#ifdef RTM_ADD
+#define FIXLEN(s) {if ((s)->sa_len == 0) (s)->sa_len = sizeof *(s);}
+#else
+#define FIXLEN(s) { }
+#endif
+
+int install = !DEBUG; /* if 1 call kernel */
+
+/*
+ * Lookup dst in the tables for an exact match.
+ */
+struct rt_entry *
+rtlookup(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int doinghost = 1;
+
+ if (dst->sa_family >= af_max)
+ return (0);
+ (*afswitch[dst->sa_family].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ goto again;
+ }
+ return (0);
+}
+
+struct sockaddr wildcard; /* zero valued cookie for wildcard searches */
+
+/*
+ * Find a route to dst as the kernel would.
+ */
+struct rt_entry *
+rtfind(dst)
+ struct sockaddr *dst;
+{
+ register struct rt_entry *rt;
+ register struct rthash *rh;
+ register u_int hash;
+ struct afhash h;
+ int af = dst->sa_family;
+ int doinghost = 1, (*match)();
+
+ if (af >= af_max)
+ return (0);
+ (*afswitch[af].af_hash)(dst, &h);
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+
+again:
+ for (rt = rh->rt_forw; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_hash != hash)
+ continue;
+ if (doinghost) {
+ if (equal(&rt->rt_dst, dst))
+ return (rt);
+ } else {
+ if (rt->rt_dst.sa_family == af &&
+ (*match)(&rt->rt_dst, dst))
+ return (rt);
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ match = afswitch[af].af_netmatch;
+ goto again;
+ }
+#ifdef notyet
+ /*
+ * Check for wildcard gateway, by convention network 0.
+ */
+ if (dst != &wildcard) {
+ dst = &wildcard, hash = 0;
+ goto again;
+ }
+#endif
+ return (0);
+}
+
+rtadd(dst, gate, metric, state)
+ struct sockaddr *dst, *gate;
+ int metric, state;
+{
+ struct afhash h;
+ register struct rt_entry *rt;
+ struct rthash *rh;
+ int af = dst->sa_family, flags;
+ u_int hash;
+
+ if (af >= af_max)
+ return;
+ (*afswitch[af].af_hash)(dst, &h);
+ flags = (*afswitch[af].af_rtflags)(dst);
+ /*
+ * Subnet flag isn't visible to kernel, move to state. XXX
+ */
+ FIXLEN(dst);
+ FIXLEN(gate);
+ if (flags & RTF_SUBNET) {
+ state |= RTS_SUBNET;
+ flags &= ~RTF_SUBNET;
+ }
+ if (flags & RTF_HOST) {
+ hash = h.afh_hosthash;
+ rh = &hosthash[hash & ROUTEHASHMASK];
+ } else {
+ hash = h.afh_nethash;
+ rh = &nethash[hash & ROUTEHASHMASK];
+ }
+ rt = (struct rt_entry *)malloc(sizeof (*rt));
+ if (rt == 0)
+ return;
+ rt->rt_hash = hash;
+ rt->rt_dst = *dst;
+ rt->rt_router = *gate;
+ rt->rt_timer = 0;
+ rt->rt_flags = RTF_UP | flags;
+ rt->rt_state = state | RTS_CHANGED;
+ rt->rt_ifp = if_ifwithdstaddr(&rt->rt_dst);
+ if (rt->rt_ifp == 0)
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ if ((state & RTS_INTERFACE) == 0)
+ rt->rt_flags |= RTF_GATEWAY;
+ rt->rt_metric = metric;
+ insque(rt, rh);
+ TRACE_ACTION("ADD", rt);
+ /*
+ * If the ioctl fails because the gateway is unreachable
+ * from this host, discard the entry. This should only
+ * occur because of an incorrect entry in /etc/gateways.
+ */
+ if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ rtioctl(ADD, &rt->rt_rt) < 0) {
+ if (errno != EEXIST && gate->sa_family < af_max)
+ syslog(LOG_ERR,
+ "adding route to net/host %s through gateway %s: %m\n",
+ (*afswitch[dst->sa_family].af_format)(dst),
+ (*afswitch[gate->sa_family].af_format)(gate));
+ perror("ADD ROUTE");
+ if (errno == ENETUNREACH) {
+ TRACE_ACTION("DELETE", rt);
+ remque(rt);
+ free((char *)rt);
+ }
+ }
+}
+
+rtchange(rt, gate, metric)
+ struct rt_entry *rt;
+ struct sockaddr *gate;
+ short metric;
+{
+ int add = 0, delete = 0, newgateway = 0;
+ struct rtuentry oldroute;
+
+ FIXLEN(gate);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (!equal(&rt->rt_router, gate)) {
+ newgateway++;
+ TRACE_ACTION("CHANGE FROM ", rt);
+ } else if (metric != rt->rt_metric)
+ TRACE_NEWMETRIC(rt, metric);
+ if ((rt->rt_state & RTS_INTERNAL) == 0) {
+ /*
+ * If changing to different router, we need to add
+ * new route and delete old one if in the kernel.
+ * If the router is the same, we need to delete
+ * the route if has become unreachable, or re-add
+ * it if it had been unreachable.
+ */
+ if (newgateway) {
+ add++;
+ if (rt->rt_metric != HOPCNT_INFINITY)
+ delete++;
+ } else if (metric == HOPCNT_INFINITY)
+ delete++;
+ else if (rt->rt_metric == HOPCNT_INFINITY)
+ add++;
+ }
+ if (delete)
+ oldroute = rt->rt_rt;
+ if ((rt->rt_state & RTS_INTERFACE) && delete) {
+ rt->rt_state &= ~RTS_INTERFACE;
+ rt->rt_flags |= RTF_GATEWAY;
+ if (metric > rt->rt_metric && delete)
+ syslog(LOG_ERR, "%s route to interface %s (timed out)",
+ add? "changing" : "deleting",
+ rt->rt_ifp ? rt->rt_ifp->int_name : "?");
+ }
+ if (add) {
+ rt->rt_router = *gate;
+ rt->rt_ifp = if_ifwithdstaddr(&rt->rt_router);
+ if (rt->rt_ifp == 0)
+ rt->rt_ifp = if_ifwithnet(&rt->rt_router);
+ }
+ rt->rt_metric = metric;
+ rt->rt_state |= RTS_CHANGED;
+ if (newgateway)
+ TRACE_ACTION("CHANGE TO ", rt);
+#ifndef RTM_ADD
+ if (add && rtioctl(ADD, &rt->rt_rt) < 0)
+ perror("ADD ROUTE");
+ if (delete && rtioctl(DELETE, &oldroute) < 0)
+ perror("DELETE ROUTE");
+#else
+ if (delete && !add) {
+ if (rtioctl(DELETE, &oldroute) < 0)
+ perror("DELETE ROUTE");
+ } else if (!delete && add) {
+ if (rtioctl(ADD, &rt->rt_rt) < 0)
+ perror("ADD ROUTE");
+ } else if (delete && add) {
+ if (rtioctl(CHANGE, &rt->rt_rt) < 0)
+ perror("CHANGE ROUTE");
+ }
+#endif
+}
+
+rtdelete(rt)
+ struct rt_entry *rt;
+{
+
+ TRACE_ACTION("DELETE", rt);
+ FIXLEN(&(rt->rt_router));
+ FIXLEN(&(rt->rt_dst));
+ if (rt->rt_metric < HOPCNT_INFINITY) {
+ if ((rt->rt_state & (RTS_INTERFACE|RTS_INTERNAL)) == RTS_INTERFACE)
+ syslog(LOG_ERR,
+ "deleting route to interface %s? (timed out?)",
+ rt->rt_ifp->int_name);
+ if ((rt->rt_state & (RTS_INTERNAL | RTS_EXTERNAL)) == 0 &&
+ rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtdelete");
+ }
+ remque(rt);
+ free((char *)rt);
+}
+
+rtdeleteall(sig)
+ int sig;
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ if (rt->rt_state & RTS_INTERFACE ||
+ rt->rt_metric >= HOPCNT_INFINITY)
+ continue;
+ TRACE_ACTION("DELETE", rt);
+ if ((rt->rt_state & (RTS_INTERNAL|RTS_EXTERNAL)) == 0 &&
+ rtioctl(DELETE, &rt->rt_rt) < 0)
+ perror("rtdeleteall");
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ exit(sig);
+}
+
+/*
+ * If we have an interface to the wide, wide world,
+ * add an entry for an Internet default route (wildcard) to the internal
+ * tables and advertise it. This route is not added to the kernel routes,
+ * but this entry prevents us from listening to other people's defaults
+ * and installing them in the kernel here.
+ */
+rtdefault()
+{
+ extern struct sockaddr inet_default;
+
+ rtadd(&inet_default, &inet_default, 1,
+ RTS_CHANGED | RTS_PASSIVE | RTS_INTERNAL);
+}
+
+rtinit()
+{
+ register struct rthash *rh;
+
+ for (rh = nethash; rh < &nethash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+ for (rh = hosthash; rh < &hosthash[ROUTEHASHSIZ]; rh++)
+ rh->rt_forw = rh->rt_back = (struct rt_entry *)rh;
+}
+
+rtioctl(action, ort)
+ int action;
+ struct rtuentry *ort;
+{
+#ifndef RTM_ADD
+ if (install == 0)
+ return (errno = 0);
+ ort->rtu_rtflags = ort->rtu_flags;
+ switch (action) {
+
+ case ADD:
+ return (ioctl(s, SIOCADDRT, (char *)ort));
+
+ case DELETE:
+ return (ioctl(s, SIOCDELRT, (char *)ort));
+
+ default:
+ return (-1);
+ }
+#else /* RTM_ADD */
+ struct {
+ struct rt_msghdr w_rtm;
+ struct sockaddr_in w_dst;
+ struct sockaddr w_gate;
+ struct sockaddr_in w_netmask;
+ } w;
+#define rtm w.w_rtm
+
+ bzero((char *)&w, sizeof(w));
+ rtm.rtm_msglen = sizeof(w);
+ rtm.rtm_version = RTM_VERSION;
+ rtm.rtm_type = (action == ADD ? RTM_ADD :
+ (action == DELETE ? RTM_DELETE : RTM_CHANGE));
+#undef rt_dst
+ rtm.rtm_flags = ort->rtu_flags;
+ rtm.rtm_seq = ++seqno;
+ rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
+ bcopy((char *)&ort->rtu_dst, (char *)&w.w_dst, sizeof(w.w_dst));
+ bcopy((char *)&ort->rtu_router, (char *)&w.w_gate, sizeof(w.w_gate));
+ w.w_dst.sin_family = AF_INET;
+ w.w_dst.sin_len = sizeof(w.w_dst);
+ w.w_gate.sa_family = AF_INET;
+ w.w_gate.sa_len = sizeof(w.w_gate);
+ if (rtm.rtm_flags & RTF_HOST) {
+ rtm.rtm_msglen -= sizeof(w.w_netmask);
+ } else {
+ register char *cp;
+ int len;
+
+ rtm.rtm_addrs |= RTA_NETMASK;
+ w.w_netmask.sin_addr.s_addr =
+ inet_maskof(w.w_dst.sin_addr.s_addr);
+ for (cp = (char *)(1 + &w.w_netmask.sin_addr);
+ --cp > (char *) &w.w_netmask; )
+ if (*cp)
+ break;
+ len = cp - (char *)&w.w_netmask;
+ if (len) {
+ len++;
+ w.w_netmask.sin_len = len;
+ len = 1 + ((len - 1) | (sizeof(long) - 1));
+ } else
+ len = sizeof(long);
+ rtm.rtm_msglen -= (sizeof(w.w_netmask) - len);
+ }
+ errno = 0;
+ return (install ? write(r, (char *)&w, rtm.rtm_msglen) : (errno = 0));
+#endif /* RTM_ADD */
+}
diff --git a/usr.sbin/routed/timer.c b/usr.sbin/routed/timer.c
new file mode 100644
index 0000000..643e2f5
--- /dev/null
+++ b/usr.sbin/routed/timer.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1983, 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[] = "@(#)timer.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#include "defs.h"
+
+int faketime;
+
+/*
+ * Timer routine. Performs routing information supply
+ * duties and manages timers on routing table entries.
+ * Management of the RTS_CHANGED bit assumes that we broadcast
+ * each time called.
+ */
+void
+timer()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1, timetobroadcast;
+ extern int externalinterfaces;
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ faketime += TIMER_RATE;
+ if (lookforinterfaces && (faketime % CHECK_INTERVAL) == 0)
+ ifinit();
+ timetobroadcast = supplier && (faketime % SUPPLY_INTERVAL) == 0;
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw) {
+ /*
+ * We don't advance time on a routing entry for
+ * a passive gateway, or any interface if we're
+ * not acting as supplier.
+ */
+ if (!(rt->rt_state & RTS_PASSIVE) &&
+ (supplier || !(rt->rt_state & RTS_INTERFACE)))
+ rt->rt_timer += TIMER_RATE;
+ if (rt->rt_timer >= GARBAGE_TIME) {
+ rt = rt->rt_back;
+ rtdelete(rt->rt_forw);
+ continue;
+ }
+ if (rt->rt_timer >= EXPIRE_TIME &&
+ rt->rt_metric < HOPCNT_INFINITY)
+ rtchange(rt, &rt->rt_router, HOPCNT_INFINITY);
+ rt->rt_state &= ~RTS_CHANGED;
+ }
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ if (timetobroadcast) {
+ toall(supply, 0, (struct interface *)NULL);
+ lastbcast = now;
+ lastfullupdate = now;
+ needupdate = 0; /* cancel any pending dynamic update */
+ nextbcast.tv_sec = 0;
+ }
+}
+
+/*
+ * On hangup, let everyone know we're going away.
+ */
+hup()
+{
+ register struct rthash *rh;
+ register struct rt_entry *rt;
+ struct rthash *base = hosthash;
+ int doinghost = 1;
+
+ if (supplier) {
+again:
+ for (rh = base; rh < &base[ROUTEHASHSIZ]; rh++) {
+ rt = rh->rt_forw;
+ for (; rt != (struct rt_entry *)rh; rt = rt->rt_forw)
+ rt->rt_metric = HOPCNT_INFINITY;
+ }
+ if (doinghost) {
+ doinghost = 0;
+ base = nethash;
+ goto again;
+ }
+ toall(supply, 0, (struct interface *)NULL);
+ }
+ exit(1);
+}
diff --git a/usr.sbin/routed/trace.c b/usr.sbin/routed/trace.c
new file mode 100644
index 0000000..f630001
--- /dev/null
+++ b/usr.sbin/routed/trace.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1983, 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.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+/*
+ * Routing Table Management Daemon
+ */
+#define RIPCMDS
+#include "defs.h"
+#include <sys/stat.h>
+#include <sys/signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include "pathnames.h"
+
+#define NRECORDS 50 /* size of circular trace buffer */
+#ifdef DEBUG
+FILE *ftrace = stdout;
+int traceactions = 0;
+#endif
+static struct timeval lastlog;
+static char *savetracename;
+
+traceinit(ifp)
+ register struct interface *ifp;
+{
+ static int iftraceinit();
+
+ if (iftraceinit(ifp, &ifp->int_input) &&
+ iftraceinit(ifp, &ifp->int_output))
+ return;
+ tracehistory = 0;
+ fprintf(stderr, "traceinit: can't init %s\n", ifp->int_name);
+}
+
+static
+iftraceinit(ifp, ifd)
+ struct interface *ifp;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+
+ ifd->ifd_records =
+ (struct iftrace *)malloc(NRECORDS * sizeof (struct iftrace));
+ if (ifd->ifd_records == 0)
+ return (0);
+ ifd->ifd_front = ifd->ifd_records;
+ ifd->ifd_count = 0;
+ for (t = ifd->ifd_records; t < ifd->ifd_records + NRECORDS; t++) {
+ t->ift_size = 0;
+ t->ift_packet = 0;
+ }
+ ifd->ifd_if = ifp;
+ return (1);
+}
+
+traceon(file)
+ char *file;
+{
+ struct stat stbuf;
+
+ if (ftrace != NULL)
+ return;
+ if (stat(file, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) != S_IFREG)
+ return;
+ savetracename = file;
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ ftrace = fopen(file, "a");
+ if (ftrace == NULL)
+ return;
+ dup2(fileno(ftrace), 1);
+ dup2(fileno(ftrace), 2);
+ traceactions = 1;
+ fprintf(ftrace, "Tracing enabled %s\n", ctime((time_t *)&now.tv_sec));
+}
+
+traceoff()
+{
+ if (!traceactions)
+ return;
+ if (ftrace != NULL) {
+ int fd = open(_PATH_DEVNULL, O_RDWR);
+
+ fprintf(ftrace, "Tracing disabled %s\n",
+ ctime((time_t *)&now.tv_sec));
+ fflush(ftrace);
+ (void) dup2(fd, 1);
+ (void) dup2(fd, 2);
+ (void) close(fd);
+ fclose(ftrace);
+ ftrace = NULL;
+ }
+ traceactions = 0;
+ tracehistory = 0;
+ tracepackets = 0;
+ tracecontents = 0;
+}
+
+void
+sigtrace(s)
+ int s;
+{
+
+ if (s == SIGUSR2)
+ traceoff();
+ else if (ftrace == NULL && savetracename)
+ traceon(savetracename);
+ else
+ bumploglevel();
+}
+
+/*
+ * Move to next higher level of tracing when -t option processed or
+ * SIGUSR1 is received. Successive levels are:
+ * traceactions
+ * traceactions + tracepackets
+ * traceactions + tracehistory (packets and contents after change)
+ * traceactions + tracepackets + tracecontents
+ */
+bumploglevel()
+{
+
+ (void) gettimeofday(&now, (struct timezone *)NULL);
+ if (traceactions == 0) {
+ traceactions++;
+ if (ftrace)
+ fprintf(ftrace, "Tracing actions started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else if (tracepackets == 0) {
+ tracepackets++;
+ tracehistory = 0;
+ tracecontents = 0;
+ if (ftrace)
+ fprintf(ftrace, "Tracing packets started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else if (tracehistory == 0) {
+ tracehistory++;
+ if (ftrace)
+ fprintf(ftrace, "Tracing history started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ } else {
+ tracepackets++;
+ tracecontents++;
+ tracehistory = 0;
+ if (ftrace)
+ fprintf(ftrace, "Tracing packet contents started %s\n",
+ ctime((time_t *)&now.tv_sec));
+ }
+ if (ftrace)
+ fflush(ftrace);
+}
+
+trace(ifd, who, p, len, m)
+ register struct ifdebug *ifd;
+ struct sockaddr *who;
+ char *p;
+ int len, m;
+{
+ register struct iftrace *t;
+
+ if (ifd->ifd_records == 0)
+ return;
+ t = ifd->ifd_front++;
+ if (ifd->ifd_front >= ifd->ifd_records + NRECORDS)
+ ifd->ifd_front = ifd->ifd_records;
+ if (ifd->ifd_count < NRECORDS)
+ ifd->ifd_count++;
+ if (t->ift_size > 0 && t->ift_size < len && t->ift_packet) {
+ free(t->ift_packet);
+ t->ift_packet = 0;
+ }
+ t->ift_stamp = now;
+ t->ift_who = *who;
+ if (len > 0 && t->ift_packet == 0) {
+ t->ift_packet = malloc(len);
+ if (t->ift_packet == 0)
+ len = 0;
+ }
+ if (len > 0)
+ bcopy(p, t->ift_packet, len);
+ t->ift_size = len;
+ t->ift_metric = m;
+}
+
+traceaction(fd, action, rt)
+ FILE *fd;
+ char *action;
+ struct rt_entry *rt;
+{
+ struct sockaddr_in *dst, *gate;
+ static struct bits {
+ int t_bits;
+ char *t_name;
+ } flagbits[] = {
+ { RTF_UP, "UP" },
+ { RTF_GATEWAY, "GATEWAY" },
+ { RTF_HOST, "HOST" },
+ { 0 }
+ }, statebits[] = {
+ { RTS_PASSIVE, "PASSIVE" },
+ { RTS_REMOTE, "REMOTE" },
+ { RTS_INTERFACE,"INTERFACE" },
+ { RTS_CHANGED, "CHANGED" },
+ { RTS_INTERNAL, "INTERNAL" },
+ { RTS_EXTERNAL, "EXTERNAL" },
+ { RTS_SUBNET, "SUBNET" },
+ { 0 }
+ };
+ register struct bits *p;
+ register int first;
+ char *cp;
+ struct interface *ifp;
+
+ if (fd == NULL)
+ return;
+ if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+ fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+ lastlog = now;
+ }
+ fprintf(fd, "%s ", action);
+ dst = (struct sockaddr_in *)&rt->rt_dst;
+ gate = (struct sockaddr_in *)&rt->rt_router;
+ fprintf(fd, "dst %s, ", inet_ntoa(dst->sin_addr));
+ fprintf(fd, "router %s, metric %d, flags",
+ inet_ntoa(gate->sin_addr), rt->rt_metric);
+ cp = " %s";
+ for (first = 1, p = flagbits; p->t_bits > 0; p++) {
+ if ((rt->rt_flags & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ fprintf(fd, " state");
+ cp = " %s";
+ for (first = 1, p = statebits; p->t_bits > 0; p++) {
+ if ((rt->rt_state & p->t_bits) == 0)
+ continue;
+ fprintf(fd, cp, p->t_name);
+ if (first) {
+ cp = "|%s";
+ first = 0;
+ }
+ }
+ fprintf(fd, " timer %d\n", rt->rt_timer);
+ if (tracehistory && !tracepackets &&
+ (rt->rt_state & RTS_PASSIVE) == 0 && rt->rt_ifp)
+ dumpif(fd, rt->rt_ifp);
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
+
+tracenewmetric(fd, rt, newmetric)
+ FILE *fd;
+ struct rt_entry *rt;
+ int newmetric;
+{
+ struct sockaddr_in *dst, *gate;
+
+ if (fd == NULL)
+ return;
+ if (lastlog.tv_sec != now.tv_sec || lastlog.tv_usec != now.tv_usec) {
+ fprintf(fd, "\n%.19s:\n", ctime((time_t *)&now.tv_sec));
+ lastlog = now;
+ }
+ dst = (struct sockaddr_in *)&rt->rt_dst;
+ gate = (struct sockaddr_in *)&rt->rt_router;
+ fprintf(fd, "CHANGE metric dst %s, ", inet_ntoa(dst->sin_addr));
+ fprintf(fd, "router %s, from %d to %d\n",
+ inet_ntoa(gate->sin_addr), rt->rt_metric, newmetric);
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
+
+dumpif(fd, ifp)
+ FILE *fd;
+ register struct interface *ifp;
+{
+ if (ifp->int_input.ifd_count || ifp->int_output.ifd_count) {
+ fprintf(fd, "*** Packet history for interface %s ***\n",
+ ifp->int_name);
+#ifdef notneeded
+ dumptrace(fd, "to", &ifp->int_output);
+#endif
+ dumptrace(fd, "from", &ifp->int_input);
+ fprintf(fd, "*** end packet history ***\n");
+ }
+}
+
+dumptrace(fd, dir, ifd)
+ FILE *fd;
+ char *dir;
+ register struct ifdebug *ifd;
+{
+ register struct iftrace *t;
+ char *cp = !strcmp(dir, "to") ? "Output" : "Input";
+
+ if (ifd->ifd_front == ifd->ifd_records &&
+ ifd->ifd_front->ift_size == 0) {
+ fprintf(fd, "%s: no packets.\n", cp);
+ fflush(fd);
+ return;
+ }
+ fprintf(fd, "%s trace:\n", cp);
+ t = ifd->ifd_front - ifd->ifd_count;
+ if (t < ifd->ifd_records)
+ t += NRECORDS;
+ for ( ; ifd->ifd_count; ifd->ifd_count--, t++) {
+ if (t >= ifd->ifd_records + NRECORDS)
+ t = ifd->ifd_records;
+ if (t->ift_size == 0)
+ continue;
+ dumppacket(fd, dir, &t->ift_who, t->ift_packet, t->ift_size,
+ &t->ift_stamp);
+ }
+}
+
+dumppacket(fd, dir, who, cp, size, stamp)
+ FILE *fd;
+ struct sockaddr_in *who; /* should be sockaddr */
+ char *dir, *cp;
+ register int size;
+ struct timeval *stamp;
+{
+ register struct rip *msg = (struct rip *)cp;
+ register struct netinfo *n;
+
+ if (fd == NULL)
+ return;
+ if (msg->rip_cmd && msg->rip_cmd < RIPCMD_MAX)
+ fprintf(fd, "%s %s %s.%d %.19s:\n", ripcmds[msg->rip_cmd],
+ dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port),
+ ctime((time_t *)&stamp->tv_sec));
+ else {
+ fprintf(fd, "Bad cmd 0x%x %s %x.%d %.19s\n", msg->rip_cmd,
+ dir, inet_ntoa(who->sin_addr), ntohs(who->sin_port));
+ fprintf(fd, "size=%d cp=%x packet=%x\n", size, cp, packet,
+ ctime((time_t *)&stamp->tv_sec));
+ fflush(fd);
+ return;
+ }
+ if (tracepackets && tracecontents == 0) {
+ fflush(fd);
+ return;
+ }
+ switch (msg->rip_cmd) {
+
+ case RIPCMD_REQUEST:
+ case RIPCMD_RESPONSE:
+ size -= 4 * sizeof (char);
+ n = msg->rip_nets;
+ for (; size > 0; n++, size -= sizeof (struct netinfo)) {
+ if (size < sizeof (struct netinfo)) {
+ fprintf(fd, "(truncated record, len %d)\n",
+ size);
+ break;
+ }
+ if (sizeof(n->rip_dst.sa_family) > 1)
+ n->rip_dst.sa_family = ntohs(n->rip_dst.sa_family);
+
+ switch ((int)n->rip_dst.sa_family) {
+
+ case AF_INET:
+ fprintf(fd, "\tdst %s metric %d\n",
+#define satosin(sa) ((struct sockaddr_in *)&sa)
+ inet_ntoa(satosin(n->rip_dst)->sin_addr),
+ ntohl(n->rip_metric));
+ break;
+
+ default:
+ fprintf(fd, "\taf %d? metric %d\n",
+ n->rip_dst.sa_family,
+ ntohl(n->rip_metric));
+ break;
+ }
+ }
+ break;
+
+ case RIPCMD_TRACEON:
+ fprintf(fd, "\tfile=%*s\n", size, msg->rip_tracefile);
+ break;
+
+ case RIPCMD_TRACEOFF:
+ break;
+ }
+ fflush(fd);
+ if (ferror(fd))
+ traceoff();
+}
diff --git a/usr.sbin/routed/trace.h b/usr.sbin/routed/trace.h
new file mode 100644
index 0000000..42521fc
--- /dev/null
+++ b/usr.sbin/routed/trace.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * @(#)trace.h 8.1 (Berkeley) 6/5/93
+ */
+
+/*
+ * Routing table management daemon.
+ */
+
+/*
+ * Trace record format.
+ */
+struct iftrace {
+ struct timeval ift_stamp; /* time stamp */
+ struct sockaddr ift_who; /* from/to */
+ char *ift_packet; /* pointer to packet */
+ short ift_size; /* size of packet */
+ short ift_metric; /* metric on associated metric */
+};
+
+/*
+ * Per interface packet tracing buffers. An incoming and
+ * outgoing circular buffer of packets is maintained, per
+ * interface, for debugging. Buffers are dumped whenever
+ * an interface is marked down.
+ */
+struct ifdebug {
+ struct iftrace *ifd_records; /* array of trace records */
+ struct iftrace *ifd_front; /* next empty trace record */
+ int ifd_count; /* number of unprinted records */
+ struct interface *ifd_if; /* for locating stuff */
+};
+
+/*
+ * Packet tracing stuff.
+ */
+int tracepackets; /* watch packets as they go by */
+int tracecontents; /* watch packet contents as they go by */
+int traceactions; /* on/off */
+int tracehistory; /* on/off */
+FILE *ftrace; /* output trace file */
+
+#define TRACE_ACTION(action, route) { \
+ if (traceactions) \
+ traceaction(ftrace, action, route); \
+ }
+#define TRACE_NEWMETRIC(route, newmetric) { \
+ if (traceactions) \
+ tracenewmetric(ftrace, route, newmetric); \
+ }
+#define TRACE_INPUT(ifp, src, pack, size) { \
+ if (tracehistory) { \
+ ifp = if_iflookup(src); \
+ if (ifp) \
+ trace(&ifp->int_input, src, pack, size, \
+ ntohl(ifp->int_metric)); \
+ } \
+ if (tracepackets) \
+ dumppacket(ftrace, "from", src, pack, size, &now); \
+ }
+#define TRACE_OUTPUT(ifp, dst, size) { \
+ if (tracehistory && ifp) \
+ trace(&ifp->int_output, dst, packet, size, ifp->int_metric); \
+ if (tracepackets) \
+ dumppacket(ftrace, "to", dst, packet, size, &now); \
+ }
diff --git a/usr.sbin/routed/trace/Makefile b/usr.sbin/routed/trace/Makefile
new file mode 100644
index 0000000..01b16b3
--- /dev/null
+++ b/usr.sbin/routed/trace/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/5/93
+
+PROG= trace
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/routed/trace/trace.c b/usr.sbin/routed/trace/trace.c
new file mode 100644
index 0000000..38c630c
--- /dev/null
+++ b/usr.sbin/routed/trace/trace.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 1983, 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) 1983, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)trace.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <protocols/routed.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct sockaddr_in myaddr;
+char packet[MAXPACKETSIZE];
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int size, s;
+ struct sockaddr from;
+ struct sockaddr_in router;
+ register struct rip *msg = (struct rip *)packet;
+ struct hostent *hp;
+ struct servent *sp;
+
+ if (argc < 3) {
+usage:
+ printf("usage: trace cmd machines,\n");
+ printf("cmd either \"on filename\", or \"off\"\n");
+ exit(1);
+ }
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ exit(2);
+ }
+ myaddr.sin_family = AF_INET;
+ myaddr.sin_port = htons(IPPORT_RESERVED-1);
+ if (bind(s, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
+ perror("bind");
+ exit(2);
+ }
+
+ argv++, argc--;
+ msg->rip_cmd = strcmp(*argv, "on") == 0 ?
+ RIPCMD_TRACEON : RIPCMD_TRACEOFF;
+ msg->rip_vers = RIPVERSION;
+ argv++, argc--;
+ size = sizeof (int);
+ if (msg->rip_cmd == RIPCMD_TRACEON) {
+ strcpy(msg->rip_tracefile, *argv);
+ size += strlen(*argv);
+ argv++, argc--;
+ }
+ if (argc == 0)
+ goto usage;
+ bzero((char *)&router, sizeof (router));
+ router.sin_family = AF_INET;
+ sp = getservbyname("router", "udp");
+ if (sp == 0) {
+ printf("udp/router: service unknown\n");
+ exit(1);
+ }
+ router.sin_port = sp->s_port;
+ while (argc > 0) {
+ router.sin_family = AF_INET;
+ router.sin_addr.s_addr = inet_addr(*argv);
+ if (router.sin_addr.s_addr == -1) {
+ hp = gethostbyname(*argv);
+ if (hp == NULL) {
+ fprintf(stderr, "trace: %s: ", *argv);
+ herror((char *)NULL);
+ continue;
+ }
+ bcopy(hp->h_addr, &router.sin_addr, hp->h_length);
+ }
+ if (sendto(s, packet, size, 0,
+ (struct sockaddr *)&router, sizeof(router)) < 0)
+ perror(*argv);
+ argv++, argc--;
+ }
+}
diff --git a/usr.sbin/rtprio/Makefile b/usr.sbin/rtprio/Makefile
new file mode 100644
index 0000000..2ca8da9
--- /dev/null
+++ b/usr.sbin/rtprio/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.5 (Berkeley) 5/11/90
+# $Id: Makefile,v 1.2 1993/11/23 00:02:21 jtc Exp $
+
+BINDIR=/usr/sbin
+PROG= rtprio
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rtprio/rtprio.1 b/usr.sbin/rtprio/rtprio.1
new file mode 100644
index 0000000..a2cc7dc
--- /dev/null
+++ b/usr.sbin/rtprio/rtprio.1
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) 1994, Henrik Vestergaard Draboel
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Henrik Vestergaard Draboel.
+.\" 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 AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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: rtprio.1,v 1.1 1994/09/01 12:05:13 davidg Exp $
+.\"
+.Dd July 23, 1994
+.Dt RTPRIO 1
+.Os
+.Sh NAME
+.Nm rtprio
+.Nd execute, examine or modify a process's realtime scheduling priority
+.Sh SYNOPSIS
+
+.Nm rtprio
+.Nm rtprio
+.Ar pid
+.Nm rtprio
+.Ar priority
+.Ar command
+.Op args
+.Nm rtprio
+.Ar priority
+.Ar -pid
+.Nm rtprio
+.Ar -t
+.Ar command
+.Op args
+.Nm rtprio
+.Ar -t
+.Ar -pid
+.Sh DESCRIPTION
+.Nm Rtprio
+is used for controlling realtime process scheduling. A process with a
+realtime priority is not subject to priority degradation, and will only
+be preempted by another process of equal or higher realtime priority.
+
+.Nm Rtprio
+called without arguments, will return the realtime priority
+of the current process.
+
+If
+.Nm rtprio
+is called with 1 argument, it will return the realtime priority
+of the process with the specified
+.Ar pid .
+
+If
+.Ar priority
+is specified, the process or program is run at that realtime priority.
+If
+.Ar -t
+is specified, the process or program is run as a normal (non-realtime)
+process.
+
+If
+.Ar -pid
+is specified, the process with that pid will be modified, else
+if
+.Ar command
+is specified, that program is run with its arguments.
+
+.Ar Priority
+is an integer between 0 (RTPRIO_MIN) and 31 (RTPRIO_MAX). 0 is the
+highest priority
+
+.Ar Pid
+of 0 means "the current process".
+
+Only root is allowed to set realtime priorities.
+.Sh RETURN VALUE
+.Nm rtprio
+returns the (new) realtime priority of the process (see rtprio(2)), or
+-1 for all usage errors.
+.Sh EXAMPLES
+.\LP
+
+To see which realtime priority the current process is at:
+.Bd -literal -offset indent -compact
+\fBrtprio\fP
+.Ed
+
+.\.LP
+To see which realtime priority of process \fI1423\fP:
+.Bd -literal -offset indent -compact
+\fBrtprio 1423\fP
+.Ed
+
+.\.LP
+To run \fIcron\fP at the lowest realtime priority:
+.Bd -literal -offset indent -compact
+\fBrtprio 31 cron\fP
+.Ed
+
+.\.LP
+To change the realtime priority of process \fI1423\fP to \fI16\fP:
+.Bd -literal -offset indent -compact
+\fBrtprio 16 -1423\fP
+.Ed
+
+.\.LP
+To run \fItcpdump\fP without realtime priority:
+.Bd -literal -offset indent -compact
+\fBrtprio -t tcpdump\fP
+.Ed
+
+.\.LP
+To change the realtime priority of process \fI1423\fP to RTRIO_RTOFF
+(no realtime):
+.Bd -literal -offset indent -compact
+\fBrtprio -t -1423\fP
+.Ed
+.Sh DIAGNOSTICS
+The
+.Nm rtprio
+utility shall exit with value of the (new) realtime priority of the
+program.
+.Sh SEE ALSO
+.Xr rtprio 2 ,
+.Xr nice 1 ,
+.Xr ps 1 ,
+.Xr nice 2 ,
+.Xr renice 8
+.Sh HISTORY
+The
+.Nm rtprio
+utility appeared in
+FreeBSD 2.0,
+but is similar to the HP-UX version.
+.Sh BUGS
+You can lock yourself out of the system by placing a cpu-intensive
+process into realtime priority.
+
+There is no way to set/view the realtime priority of process 0
+(swapper) (see ps(1)).
+
+Others ...
+.Sh AUTHOR
+Henrik Vestergaard Draboel - hvd@terry.ping.dk
diff --git a/usr.sbin/rtprio/rtprio.c b/usr.sbin/rtprio/rtprio.c
new file mode 100644
index 0000000..cc66fd4
--- /dev/null
+++ b/usr.sbin/rtprio/rtprio.c
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+/* Copyright (c) 1994 Henrik Vestergaard Drabøl (hvd@terry.pping.dk) */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1989 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+/*static char sccsid[] = "from: @(#)rtprio.c 5.4 (Berkeley) 6/1/90";*/
+static char rcsid[] = "$Id: rtprio.c,v 1.2 1993/11/23 00:02:23 jtc Exp $";
+#endif /* not lint */
+
+#include <sys/time.h>
+#include <stdio.h>
+#include <sys/rtprio.h>
+#include <locale.h>
+#include <errno.h>
+#include <err.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+static void usage();
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int nrtprio = RTPRIO_RTOFF;
+ int proc=0;
+
+ setlocale(LC_ALL, "");
+ errno = 0;
+
+ switch (argc) {
+ case 2:
+ proc = abs(atoi(argv[1]));
+ /* FALLTHROUGH */
+
+ case 1:
+ nrtprio = rtprio(proc,RTPRIO_NOCHG);
+ fprintf(stderr,"rtprio: %d %s\n",
+ nrtprio,
+ nrtprio==RTPRIO_RTOFF?"(RTOFF)":"");
+ exit(nrtprio);
+ /* NOTREACHED */
+
+ default: {
+ switch (argv[1][0]) {
+ case '-':
+ if (strcmp(argv[1],"-t")==0)
+ nrtprio = RTPRIO_RTOFF;
+ else
+ usage();
+ break;
+
+ case '0':case '1':case '2':case '3':case '4':
+ case '5':case '6':case '7':case '8':case '9':
+ nrtprio = atoi (argv[1]);
+
+ if (errno== ERANGE) usage();
+ break;
+
+ default:
+ usage();
+ break;
+ }
+ switch (argv[2][0]) {
+ case '-':
+ proc = -atoi(argv[2]);
+
+ break;
+ }
+
+ errno = 0;
+
+ nrtprio = rtprio(proc, nrtprio);
+
+ if (errno) {
+ err (1, "rtprio");
+ /* NOTREACHED */
+ }
+
+ if (proc == 0) {
+ execvp(argv[2], &argv[2]);
+ err ((errno == ENOENT) ? 127 : 126, "%s", argv[2]);}
+ /* NOTREACHED */
+ }
+ }
+return(nrtprio);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: rtprio\n");
+ (void)fprintf(stderr, "usage: rtprio [-] pid\n");
+ (void)fprintf(stderr, "usage: rtprio priority command [ args ] \n");
+ (void)fprintf(stderr, "usage: rtprio priority -pid \n");
+ (void)fprintf(stderr, "usage: rtprio -t command [ args ] \n");
+ (void)fprintf(stderr, "usage: rtprio -t -pid \n");
+
+ exit(-1);
+}
diff --git a/usr.sbin/rwhod/Makefile b/usr.sbin/rwhod/Makefile
new file mode 100644
index 0000000..0f884f5
--- /dev/null
+++ b/usr.sbin/rwhod/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= rwhod
+MAN8= rwhod.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rwhod/rwhod.8 b/usr.sbin/rwhod/rwhod.8
new file mode 100644
index 0000000..2922bcc
--- /dev/null
+++ b/usr.sbin/rwhod/rwhod.8
@@ -0,0 +1,146 @@
+.\" 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.
+.\"
+.\" @(#)rwhod.8 8.2 (Berkeley) 12/11/93
+.\"
+.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 /kernel
+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 0000000..75c02ff
--- /dev/null
+++ b/usr.sbin/rwhod/rwhod.c
@@ -0,0 +1,539 @@
+/*
+ * 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";
+#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 0000000..76670e5
--- /dev/null
+++ b/usr.sbin/sa/Makefile
@@ -0,0 +1,7 @@
+# $Id: Makefile,v 1.1.1.1 1994/09/26 21:22:55 davidg Exp $
+
+PROG= sa
+MAN8= 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 0000000..6d52914
--- /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 1994/03/24 18:41:50 cgd 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 0000000..dac2724
--- /dev/null
+++ b/usr.sbin/sa/main.c
@@ -0,0 +1,542 @@
+/*
+ * 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 1994/03/24 18:41:51 cgd 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 <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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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;
+
+ c1 = (struct cmdinfo *) d1->data;
+ c2 = (struct cmdinfo *) d2->data;
+
+ 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 0000000..31721c2
--- /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 1994/03/24 18:41:53 cgd 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 0000000..083f9da
--- /dev/null
+++ b/usr.sbin/sa/pdb.c
@@ -0,0 +1,418 @@
+/*
+ * 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 1994/03/24 18:41:54 cgd Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.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;
+
+ bcopy(ci->ci_comm, &keydata, 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 */
+ bcopy(data.data, &newci, data.size);
+ } else { /* it's not there; zero it and copy the key */
+ bzero(&newci, sizeof newci);
+ bcopy(key.data, newci.ci_comm, 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;
+
+ bzero(&ci_total, sizeof ci_total);
+ strcpy(ci_total.ci_comm, "");
+ bzero(&ci_other, sizeof ci_other);
+ strcpy(ci_other.ci_comm, "***other");
+ bzero(&ci_junk, 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'
+ */
+ bzero(&bti, 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;
+ bcopy(cip, &ci, 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;
+ bcopy(cip, &ci, 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 0000000..09a15fd
--- /dev/null
+++ b/usr.sbin/sa/sa.8
@@ -0,0 +1,240 @@
+.\"
+.\" 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 1994/09/26 21:22:56 davidg Exp $
+.\"
+.Dd February 25, 1994
+.Dt SA 8
+.Os
+.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 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
+The 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 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 0000000..af7d0fd
--- /dev/null
+++ b/usr.sbin/sa/usrdb.c
@@ -0,0 +1,282 @@
+/*
+ * 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 1994/03/24 18:42:01 cgd Exp $";
+#endif
+
+#include <sys/types.h>
+#include <sys/acct.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.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;
+
+ bzero(&bti, 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 */
+ bcopy(data.data, &newui, 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 */
+ bzero(&newui, 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;
+
+ bzero(&bti, 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 *ui;
+ double t;
+ int rv;
+
+ rv = DB_SEQ(usracct_db, &key, &data, R_FIRST);
+ if (rv < 0)
+ warn("retrieving user accounting stats");
+
+ while (rv == 0) {
+ ui = (struct userinfo *) data.data;
+
+ 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;
+
+ bcopy(k1->data, &d1, sizeof d1);
+ bcopy(k2->data, &d2, sizeof d2);
+
+ if (d1 < d2)
+ return -1;
+ else if (d1 == d2)
+ return 0;
+ else
+ return 1;
+}
diff --git a/usr.sbin/sendmail/FAQ b/usr.sbin/sendmail/FAQ
new file mode 100644
index 0000000..743dc36
--- /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 0000000..f34c6b7
--- /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 0000000..3b21e37
--- /dev/null
+++ b/usr.sbin/sendmail/Makefile
@@ -0,0 +1,24 @@
+# @(#)Makefile 8.4 (Berkeley) 4/22/94
+
+SUBDIR= src mailstats makemap praliases cf/cf
+FTPDIR= barad-dur:/disks/barad-dur/ftp/sendmail/.
+VER= XX
+
+tar: Files.base Files.cf Files.misc Files.xdoc
+ (cd src; ${MAKE})
+ (cd doc; PRINTER=ps ${MAKE})
+ (cd doc; chmod 444 op/op.ps intro/intro.ps usenix/usenix.ps)
+ (cd cf/cf; ${MAKE})
+ pax -w -x tar -L -f sendmail.${VER}.base.tar `grep -v ^# Files.base`
+ compress sendmail.${VER}.base.tar
+ pax -w -x tar -L -f sendmail.${VER}.cf.tar `grep -v ^# Files.cf`
+ compress sendmail.${VER}.cf.tar
+ pax -w -x tar -L -f sendmail.${VER}.misc.tar `grep -v ^# Files.misc`
+ compress sendmail.${VER}.misc.tar
+ pax -w -x tar -L -f sendmail.${VER}.xdoc.tar `grep -v ^# Files.xdoc`
+ compress sendmail.${VER}.xdoc.tar
+
+ftp: sendmail.${VER}.base.tar.Z sendmail.${VER}.cf.tar.Z sendmail.${VER}.misc.tar.Z sendmail.${VER}.xdoc.tar.Z
+ rcp sendmail.${VER}.*.tar.Z RELEASE_NOTES FAQ KNOWNBUGS ${FTPDIR}
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/sendmail/READ_ME b/usr.sbin/sendmail/READ_ME
new file mode 100644
index 0000000..016fa7f
--- /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 0000000..8f7e9e8
--- /dev/null
+++ b/usr.sbin/sendmail/RELEASE_NOTES
@@ -0,0 +1,2556 @@
+ SENDMAIL RELEASE NOTES
+ @(#)RELEASE_NOTES 8.6.9.3 (Berkeley) 4/19/94
+
+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.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 0000000..6ab3b01
--- /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 0000000..05613df
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/Makefile
@@ -0,0 +1,86 @@
+# @(#)Makefile 8.5 (Berkeley) 12/1/93
+
+M4= m4
+#M4= /usr/src/usr.bin/m4/obj/m4
+CHMOD= chmod
+ROMODE= 444
+RM= rm -f
+
+.SUFFIXES: .mc .cf
+
+.mc.cf:
+ $(RM) $@
+ (cd ${.CURDIR} && $(M4) ${@:R}.mc > obj/$@)
+ $(CHMOD) $(ROMODE) $@
+
+ALL= cs-hidden.cf cs-exposed.cf \
+ hpux-cs-exposed.cf hpux-cs-hidden.cf \
+ riscos-cs-exposed.cf \
+ sunos3.5-cs-exposed.cf sunos3.5-cs-hidden.cf \
+ sunos4.1-cs-exposed.cf sunos4.1-cs-hidden.cf \
+ ultrix4.1-cs-exposed.cf ultrix4.1-cs-hidden.cf \
+ osf1-cs-exposed.cf osf1-cs-hidden.cf \
+ mail.cs.cf mail.eecs.cf ucbvax.cf vangogh.cf \
+ chez.cf knecht.cf cogsci.cf alpha.cf s2k.cf auspex.cf \
+ python.cf \
+ clientproto.cf tcpproto.cf uucpproto.cf
+
+all: $(ALL)
+
+clean cleandir:
+ $(RM) $(ALL) core
+
+depend install:
+
+# 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/aix3.m4 \
+ ../ostype/bsd4.3.m4 \
+ ../ostype/bsd4.4.m4 \
+ ../ostype/hpux.m4 \
+ ../ostype/irix.m4 \
+ ../ostype/linux.m4 \
+ ../ostype/nextstep.m4 \
+ ../ostype/osf1.m4 \
+ ../ostype/riscos4.5.m4 \
+ ../ostype/solaris2.m4 \
+ ../ostype/sunos3.5.m4 \
+ ../ostype/sunos4.1.m4 \
+ ../ostype/svr4.m4 \
+ ../ostype/ultrix4.1.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/Makefile.dist b/usr.sbin/sendmail/cf/cf/Makefile.dist
new file mode 100644
index 0000000..074529e
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/Makefile.dist
@@ -0,0 +1,85 @@
+#
+# Makefile for configuration files.
+#
+# @(#)Makefile.dist 8.1 (Berkeley) 8/25/93
+
+M4= m4
+#M4= /usr/src/usr.bin/m4/obj/m4
+CHMOD= chmod
+ROMODE= 444
+RM= rm -f
+
+.SUFFIXES: .mc .cf
+
+.mc.cf:
+ $(RM) $@
+ $(M4) $*.mc > $@
+ $(CHMOD) $(ROMODE) $@
+
+ALL= cs-hidden.cf cs-exposed.cf \
+ hpux-cs-exposed.cf hpux-cs-hidden.cf \
+ sunos3.5-cs-exposed.cf sunos3.5-cs-hidden.cf \
+ sunos4.1-cs-exposed.cf sunos4.1-cs-hidden.cf \
+ ultrix4.1-cs-exposed.cf ultrix4.1-cs-hidden.cf \
+ mail.cs.cf mail.eecs.cf ucbvax.cf vangogh.cf \
+ chez.cf knecht.cf cogsci.cf alpha.cf s2k.cf auspex.cf \
+ python.cf \
+ clientproto.cf tcpproto.cf uucpproto.cf
+
+all: $(ALL)
+
+clean cleandir:
+ $(RM) $(ALL) core
+
+depend install:
+
+# 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/aix3.m4 \
+ ../ostype/bsd4.3.m4 \
+ ../ostype/bsd4.4.m4 \
+ ../ostype/hpux.m4 \
+ ../ostype/irix.m4 \
+ ../ostype/linux.m4 \
+ ../ostype/nextstep.m4 \
+ ../ostype/osf1.m4 \
+ ../ostype/riscos4.5.m4 \
+ ../ostype/solaris2.m4 \
+ ../ostype/sunos3.5.m4 \
+ ../ostype/sunos4.1.m4 \
+ ../ostype/svr4.m4 \
+ ../ostype/ultrix4.1.m4 \
+ ../siteconfig/uucp.cogsci.m4 \
+ ../siteconfig/uucp.old.arpa.m4 \
+ ../siteconfig/uucp.ucbarpa.m4 \
+ ../siteconfig/uucp.ucbvax.m4 \
+
+$(ALL): $(M4FILES)
diff --git a/usr.sbin/sendmail/cf/cf/alpha.mc b/usr.sbin/sendmail/cf/cf/alpha.mc
new file mode 100644
index 0000000..026fed1
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/alpha.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)alpha.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(osf1)dnl
+DOMAIN(s2k)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/auspex.mc b/usr.sbin/sendmail/cf/cf/auspex.mc
new file mode 100644
index 0000000..961c139
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/auspex.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)auspex.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos4.1)dnl
+DOMAIN(cs.hidden)dnl
+FEATURE(use_cw_file)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/chez.mc b/usr.sbin/sendmail/cf/cf/chez.mc
new file mode 100644
index 0000000..13f9519
--- /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/clientproto.mc b/usr.sbin/sendmail/cf/cf/clientproto.mc
new file mode 100644
index 0000000..902c1eb
--- /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/cogsci.mc b/usr.sbin/sendmail/cf/cf/cogsci.mc
new file mode 100644
index 0000000..4faa46d
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/cogsci.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)cogsci.mc 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.exposed)dnl
+MAILER(smtp)dnl
+MAILER(uucp)dnl
+SITECONFIG(uucp.cogsci, Ucogsci, U)
diff --git a/usr.sbin/sendmail/cf/cf/cs-exposed.mc b/usr.sbin/sendmail/cf/cf/cs-exposed.mc
new file mode 100644
index 0000000..62072b7
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)cs-exposed.mc 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/cs-hidden.mc b/usr.sbin/sendmail/cf/cf/cs-hidden.mc
new file mode 100644
index 0000000..216062c
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)cs-hidden.mc 8.1 (Berkeley) 6/7/93')
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/freefall.mc b/usr.sbin/sendmail/cf/cf/freefall.mc
new file mode 100644
index 0000000..a27e9f8
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/freefall.mc
@@ -0,0 +1,47 @@
+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(`@(#)freefall.mc $Revision: 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(`confCHECKPOINT_INTERVAL', 4)dnl
+define(`confAUTO_REBUILD', True)dnl
+
+
diff --git a/usr.sbin/sendmail/cf/cf/hpux-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/hpux-cs-exposed.mc
new file mode 100644
index 0000000..4f61ffd
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/hpux-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)hpux-cs-exposed.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(hpux)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/hpux-cs-hidden.mc b/usr.sbin/sendmail/cf/cf/hpux-cs-hidden.mc
new file mode 100644
index 0000000..33cf580
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/hpux-cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)hpux-cs-hidden.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(hpux)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/knecht.mc b/usr.sbin/sendmail/cf/cf/knecht.mc
new file mode 100644
index 0000000..0cd17fa
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/knecht.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(`@(#)knecht.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(ultrix4.1)dnl
+DOMAIN(cs.exposed)dnl
+define(`LOCAL_RELAY', CS.Berkeley.EDU)dnl
+MAILER(smtp)dnl
+
+# our local domain
+DDCS.Berkeley.EDU
diff --git a/usr.sbin/sendmail/cf/cf/mail.cs.mc b/usr.sbin/sendmail/cf/cf/mail.cs.mc
new file mode 100644
index 0000000..227e2fe
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/mail.cs.mc
@@ -0,0 +1,55 @@
+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(`@(#)mail.cs.mc 8.3 (Berkeley) 10/15/93')
+OSTYPE(ultrix4.1)dnl
+DOMAIN(Berkeley)dnl
+MASQUERADE_AS(CS.Berkeley.EDU)dnl
+FEATURE(notsticky)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`confUSERDB_SPEC', ``/usr/local/lib/users.cs.db,/usr/local/lib/users.eecs.db'')dnl
+DDBerkeley.EDU
+
+# hosts for which we accept and forward mail (must be in .Berkeley.EDU)
+CF CS
+FF/etc/sendmail.cw
+
+LOCAL_RULE_0
+R< @ $=F . $D . > : $* $@ $>7 $2 @here:... -> ...
+R$* $=O $* < @ $=F . $D . > $@ $>7 $1 $2 $3 ...@here -> ...
+
+R$* < @ $=F . $D . > $#local $: $1 use UDB
diff --git a/usr.sbin/sendmail/cf/cf/mail.eecs.mc b/usr.sbin/sendmail/cf/cf/mail.eecs.mc
new file mode 100644
index 0000000..3b6200c
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/mail.eecs.mc
@@ -0,0 +1,54 @@
+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(`@(#)mail.eecs.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(ultrix4.1)dnl
+DOMAIN(eecs.hidden)dnl
+FEATURE(notsticky)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
+define(`confUSERDB_SPEC', `/usr/local/lib/users.cs.db,/usr/local/lib/users.eecs.db')dnl
+DDBerkeley.EDU
+
+# hosts for which we accept and forward mail (must be in .Berkeley.EDU)
+CF EECS
+FF/etc/sendmail.cw
+
+LOCAL_RULE_0
+R< @ $=F . $D . > : $* $@ $>7 $2 @here:... -> ...
+R$* $=O $* < @ $=F . $D . > $@ $>7 $1 $2 $3 ...@here -> ...
+
+R$* < @ $=F . $D . > $#local $: $1 use UDB
diff --git a/usr.sbin/sendmail/cf/cf/osf1-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/osf1-cs-exposed.mc
new file mode 100644
index 0000000..eaed6cc
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/osf1-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)osf1-cs-exposed.mc 8.1 (Berkeley) 10/15/93')
+OSTYPE(osf1)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/osf1-cs-hidden.mc b/usr.sbin/sendmail/cf/cf/osf1-cs-hidden.mc
new file mode 100644
index 0000000..2b85ba4
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/osf1-cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)osf1-cs-hidden.mc 8.1 (Berkeley) 10/15/93')
+OSTYPE(osf1)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/python.mc b/usr.sbin/sendmail/cf/cf/python.mc
new file mode 100644
index 0000000..ac23e61
--- /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/riscos-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/riscos-cs-exposed.mc
new file mode 100644
index 0000000..a92b770
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/riscos-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)riscos-cs-exposed.mc 8.1 (Berkeley) 12/1/93')
+OSTYPE(riscos4.5)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/s2k.mc b/usr.sbin/sendmail/cf/cf/s2k.mc
new file mode 100644
index 0000000..e65fc9f
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/s2k.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)s2k.mc 8.1 (Berkeley) 6/7/93')
+OLDSENDMAIL
+OSTYPE(ultrix4.1)dnl
+DOMAIN(s2k)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/sample.mc b/usr.sbin/sendmail/cf/cf/sample.mc
new file mode 100644
index 0000000..760409d
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sample.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sample.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(bsd4.4)
+DOMAIN(cs.hidden)
+MAILER(smtp)
diff --git a/usr.sbin/sendmail/cf/cf/sleepy.mc b/usr.sbin/sendmail/cf/cf/sleepy.mc
new file mode 100644
index 0000000..ff6a7cd
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sleepy.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(@(#)sleepy.mc 8.1 (Berkeley) 6/7/93)
+OSTYPE(hpux)dnl
+DOMAIN(cs.exposed)dnl
+define(`LOCAL_RELAY', diva.Berkeley.EDU)dnl
+define(`MASQUERADE_NAME', diva.Berkeley.EDU)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/sunos3.5-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/sunos3.5-cs-exposed.mc
new file mode 100644
index 0000000..46d04d9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sunos3.5-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sunos3.5-cs-exposed.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos3.5)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/sunos3.5-cs-hidden.mc b/usr.sbin/sendmail/cf/cf/sunos3.5-cs-hidden.mc
new file mode 100644
index 0000000..a3d6f20
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sunos3.5-cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sunos3.5-cs-hidden.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos3.5)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/sunos4.1-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/sunos4.1-cs-exposed.mc
new file mode 100644
index 0000000..7c94ba5
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sunos4.1-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sunos4.1-cs-exposed.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos4.1)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/sunos4.1-cs-hidden.mc b/usr.sbin/sendmail/cf/cf/sunos4.1-cs-hidden.mc
new file mode 100644
index 0000000..8e1dbb9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/sunos4.1-cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)sunos4.1-cs-hidden.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos4.1)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/tcpproto.mc b/usr.sbin/sendmail/cf/cf/tcpproto.mc
new file mode 100644
index 0000000..aa31ca1
--- /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/ucbarpa.mc b/usr.sbin/sendmail/cf/cf/ucbarpa.mc
new file mode 100644
index 0000000..21f35fd
--- /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 0000000..bae55d5
--- /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.3)
+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/udb.mc b/usr.sbin/sendmail/cf/cf/udb.mc
new file mode 100644
index 0000000..624d2d4
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/udb.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)udb.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(sunos4.1)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(smtp)dnl
+define(`USERDB_FILE', `/home/auspex/a/staff/gnn/UDB/UI')dnl
diff --git a/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-exposed.mc b/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-exposed.mc
new file mode 100644
index 0000000..093590f
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-exposed.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)ultrix4.1-cs-exposed.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(ultrix4.1)dnl
+DOMAIN(cs.exposed)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-hidden.mc b/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-hidden.mc
new file mode 100644
index 0000000..ea25375
--- /dev/null
+++ b/usr.sbin/sendmail/cf/cf/ultrix4.1-cs-hidden.mc
@@ -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.
+#
+
+include(`../m4/cf.m4')
+VERSIONID(`@(#)ultrix4.1-cs-hidden.mc 8.1 (Berkeley) 6/7/93')
+OSTYPE(ultrix4.1)dnl
+DOMAIN(cs.hidden)dnl
+MAILER(local)dnl
+MAILER(smtp)dnl
diff --git a/usr.sbin/sendmail/cf/cf/uucpproto.mc b/usr.sbin/sendmail/cf/cf/uucpproto.mc
new file mode 100644
index 0000000..c460d76
--- /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 0000000..2406364
--- /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 0000000..4f572d6
--- /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 0000000..43c07be
--- /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 0000000..3d9721a
--- /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 0000000..bbdc01a
--- /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 0000000..25b931f
--- /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 0000000..c7cbffa
--- /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 0000000..dd572c8
--- /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 0000000..85c8cf0
--- /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 0000000..bfad1bc
--- /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 0000000..fa39997
--- /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 0000000..0157e6b
--- /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 0000000..465a5ae
--- /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 0000000..5118923
--- /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 0000000..8723437
--- /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 0000000..930f265
--- /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 0000000..0f2199c
--- /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 0000000..33b5ad5
--- /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 0000000..77cc97b
--- /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 0000000..4f270c0
--- /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 0000000..528cbff
--- /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 0000000..c79d179
--- /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 0000000..2845729
--- /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 0000000..19806ff
--- /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.9.1 (Berkeley) 4/18/94')
+#
+divert(0)
+# Configuration version number
+DZ8.6.9
diff --git a/usr.sbin/sendmail/cf/mailer/fax.m4 b/usr.sbin/sendmail/cf/mailer/fax.m4
new file mode 100644
index 0000000..0c98a3b
--- /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 0000000..24a8204
--- /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 0000000..92bcff9
--- /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 0000000..45efbd6
--- /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 0000000..fe6ee30
--- /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 0000000..dd7aa87
--- /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/aix3.m4 b/usr.sbin/sendmail/cf/ostype/aix3.m4
new file mode 100644
index 0000000..4411fd0
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/aix3.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(`@(#)aix3.m4 8.3 (Berkeley) 8/8/93')
+define(`LOCAL_MAILER_PATH', /bin/bellmail)dnl
+define(`LOCAL_MAILER_ARGS', mail $u)dnl
+define(`LOCAL_MAILER_FLAGS', `mn')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/aux.m4 b/usr.sbin/sendmail/cf/ostype/aux.m4
new file mode 100644
index 0000000..b7ea47b
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/aux.m4
@@ -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.
+#
+
+divert(0)
+VERSIONID(`@(#)aux.m4 8.1 (Berkeley) 9/2/93')
+define(`ALIAS_FILE', /usr/lib/aliases)dnl
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`STATUS_FILE', /usr/lib/sendmail.st)dnl
+define(`UUCP_MAILER_PATH', /usr/bin/uux)dnl
+define(`LOCAL_MAILER_FLAGS', mn)dnl
+define(`LOCAL_MAILER_ARGS', `mail -d -r $f $u')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/bsd4.3.m4 b/usr.sbin/sendmail/cf/ostype/bsd4.3.m4
new file mode 100644
index 0000000..32aac4d
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/bsd4.3.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.
+#
+
+divert(0)
+VERSIONID(`@(#)bsd4.3.m4 8.2 (Berkeley) 2/10/94')
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`UUCP_MAILER_ARGS', `uux - -r -z -a$f $h!rmail ($u)')dnl
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 0000000..1950528
--- /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/ostype/bsdi1.0.m4 b/usr.sbin/sendmail/cf/ostype/bsdi1.0.m4
new file mode 100644
index 0000000..28088f0
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/bsdi1.0.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(`@(#)bsdi1.0.m4 8.1 (Berkeley) 12/11/93')dnl
+OSTYPE(bsd4.4)
diff --git a/usr.sbin/sendmail/cf/ostype/dgux.m4 b/usr.sbin/sendmail/cf/ostype/dgux.m4
new file mode 100644
index 0000000..38c1c1a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/dgux.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.
+#
+
+divert(0)
+VERSIONID(`@(#)dgux.m4 8.1 (Berkeley) 11/27/93')
+define(`LOCAL_MAILER_FLAGS', m)dnl
+define(`confTIME_ZONE', `USE_TZ')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/domainos.m4 b/usr.sbin/sendmail/cf/ostype/domainos.m4
new file mode 100644
index 0000000..6c214e6
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/domainos.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(`@(#)domainos.m4 8.1 (Berkeley) 1/23/94')
+divert(-1)
+
+define(`ALIAS_FILE', /usr/lib/aliases)
+define(`STATUS_FILE', /usr/lib/sendmail.st)
+define(`QUEUE_DIR', /usr/spool/mqueue)
diff --git a/usr.sbin/sendmail/cf/ostype/dynix3.2.m4 b/usr.sbin/sendmail/cf/ostype/dynix3.2.m4
new file mode 100644
index 0000000..a4d6e52
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/dynix3.2.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.
+#
+
+divert(0)
+VERSIONID(`@(#)dynix3.2.m4 8.1 (Berkeley) 11/27/93')
+define(`ALIAS_FILE', /usr/lib/aliases)dnl
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
diff --git a/usr.sbin/sendmail/cf/ostype/hpux.m4 b/usr.sbin/sendmail/cf/ostype/hpux.m4
new file mode 100644
index 0000000..1be21f3
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/hpux.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(`@(#)hpux.m4 8.5 (Berkeley) 1/9/94')
+
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`ALIAS_FILE', /usr/lib/aliases)dnl
+define(`STATUS_FILE', /usr/lib/sendmail.st)dnl
+define(`LOCAL_MAILER_FLAGS', `m')dnl
+define(`UUCP_MAILER_ARGS', `uux - -r -a$f -gC $h!rmail ($u)')dnl
+define(`confTIME_ZONE', `USE_TZ')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/irix.m4 b/usr.sbin/sendmail/cf/ostype/irix.m4
new file mode 100644
index 0000000..6cd7fc9
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/irix.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(`@(#)irix.m4 8.4 (Berkeley) 2/1/94')
+define(`LOCAL_MAILER_FLAGS', Ehm)dnl
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`ALIAS_FILE', /usr/lib/aliases)dnl
+define(`STATUS_FILE', /usr/lib/sendmail.st)dnl
diff --git a/usr.sbin/sendmail/cf/ostype/linux.m4 b/usr.sbin/sendmail/cf/ostype/linux.m4
new file mode 100644
index 0000000..527b6fa
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/linux.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(`@(#)linux.m4 8.2 (Berkeley) 8/21/93')
+define(`LOCAL_MAILER_PATH', /bin/mail.local)dnl
diff --git a/usr.sbin/sendmail/cf/ostype/nextstep.m4 b/usr.sbin/sendmail/cf/ostype/nextstep.m4
new file mode 100644
index 0000000..8144c3e
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/nextstep.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(`@(#)nextstep.m4 8.4 (Berkeley) 11/30/93')
+define(`ALIAS_FILE', /etc/sendmail/aliases)dnl
+define(`HELP_FILE', /usr/lib/sendmail.hf)dnl
+define(`STATUS_FILE', /etc/sendmail/sendmail.st)dnl
+define(`UUCP_MAILER_PATH', /usr/bin/uux)dnl
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`LOCAL_MAILER_FLAGS', `rmnP')dnl
+define(`LOCAL_SHELL_FLAGS', `euP')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/osf1.m4 b/usr.sbin/sendmail/cf/ostype/osf1.m4
new file mode 100644
index 0000000..fbc4832
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/osf1.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(`@(#)osf1.m4 8.1 (Berkeley) 6/7/93')
+ifdef(`_OLD_SENDMAIL_', `define(`NEED_DOMAIN', `')')dnl
+define(`ALIAS_FILE', /usr/adm/sendmail/aliases)dnl
+define(`STATUS_FILE', /usr/adm/sendmail/sendmail.st)dnl
+define(`HELP_FILE', /usr/share/lib/sendmail.hf)dnl
diff --git a/usr.sbin/sendmail/cf/ostype/riscos4.5.m4 b/usr.sbin/sendmail/cf/ostype/riscos4.5.m4
new file mode 100644
index 0000000..b45b252
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/riscos4.5.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(`@(#)riscos4.5.m4 8.2 (Berkeley) 12/1/93')
+
+define(`LOCAL_MAILER_ARGS', `rmail -d $u')dnl
+define(`ALIAS_FILE', `/usr/lib/aliases')dnl
+define(`QUEUE_DIR', `/usr/spool/mqueue')dnl
+define(`HELP_FILE', `/usr/lib/sendmail.hf')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/sco3.2.m4 b/usr.sbin/sendmail/cf/ostype/sco3.2.m4
new file mode 100644
index 0000000..08ed0fd
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/sco3.2.m4
@@ -0,0 +1,45 @@
+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(`@(#)sco32.m4 8.1 (Berkeley) 11/27/93')
+define(`ALIAS_FILE', /usr/lib/mail/aliases)dnl
+define(`QUEUE_DIR', /usr/spool/mqueue)dnl
+define(`STATUS_FILE', /usr/lib/sendmail.st)dnl
+define(`UUCP_MAILER_PATH', /usr/bin/uux)dnl
+define(`LOCAL_MAILER_PATH', /usr/bin/lmail)dnl
+define(`LOCAL_MAILER_FLAGS', PuhCE)dnl
+define(`LOCAL_MAILER_ARGS', `lmail $u')dnl
+define(`LOCAL_SHELL_FLAGS', Peu)dnl
diff --git a/usr.sbin/sendmail/cf/ostype/solaris2.m4 b/usr.sbin/sendmail/cf/ostype/solaris2.m4
new file mode 100644
index 0000000..5e87027
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/solaris2.m4
@@ -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.
+#
+
+divert(0)
+VERSIONID(`@(#)solaris2.m4 8.2 (Berkeley) 1/23/94')
+divert(-1)
+
+define(`ALIAS_FILE', /etc/mail/aliases)
+define(`HELP_FILE', /etc/mail/sendmail.hf)
+define(`STATUS_FILE', /etc/mail/sendmail.st)
+define(`LOCAL_MAILER_FLAGS', `fSn')
diff --git a/usr.sbin/sendmail/cf/ostype/sunos3.5.m4 b/usr.sbin/sendmail/cf/ostype/sunos3.5.m4
new file mode 100644
index 0000000..fe76931
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/sunos3.5.m4
@@ -0,0 +1,37 @@
+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(`@(#)sunos3.5.m4 8.1 (Berkeley) 6/7/93')
diff --git a/usr.sbin/sendmail/cf/ostype/sunos4.1.m4 b/usr.sbin/sendmail/cf/ostype/sunos4.1.m4
new file mode 100644
index 0000000..cfa7a9a
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/sunos4.1.m4
@@ -0,0 +1,37 @@
+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(`@(#)sunos4.1.m4 8.1 (Berkeley) 6/7/93')
diff --git a/usr.sbin/sendmail/cf/ostype/svr4.m4 b/usr.sbin/sendmail/cf/ostype/svr4.m4
new file mode 100644
index 0000000..dd50127
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/svr4.m4
@@ -0,0 +1,45 @@
+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(`@(#)svr4.m4 8.1 (Berkeley) 8/24/93')
+
+ifdef(`ALIAS_FILE',,`define(`ALIAS_FILE', /usr/ucblib/aliases)')dnl
+ifdef(`HELP_FILE',,`define(`HELP_FILE', /usr/ucblib/sendmail.hf)')dnl
+ifdef(`STATUS_FILE',,`define(`STATUS_FILE', /usr/ucblib/sendmail.st)')dnl
+define(`LOCAL_MAILER_PATH', `/usr/ucblib/binmail')dnl
+define(`LOCAL_MAILER_FLAGS', `rmn')dnl
+define(`LOCAL_SHELL_FLAGS', `ehuP')dnl
+define(`UUCP_MAILER_ARGS', `uux - -r -a$f -gmedium $h!rmail ($u)')dnl
diff --git a/usr.sbin/sendmail/cf/ostype/ultrix4.1.m4 b/usr.sbin/sendmail/cf/ostype/ultrix4.1.m4
new file mode 100644
index 0000000..87c4425
--- /dev/null
+++ b/usr.sbin/sendmail/cf/ostype/ultrix4.1.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(`@(#)ultrix4.1.m4 8.1 (Berkeley) 6/7/93')
+ifdef(`_OLD_SENDMAIL_', `define(`NEED_DOMAIN', `')')dnl
diff --git a/usr.sbin/sendmail/cf/sh/makeinfo.sh b/usr.sbin/sendmail/cf/sh/makeinfo.sh
new file mode 100644
index 0000000..dd5044a
--- /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 0000000..33c7151
--- /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 0000000..81d5e94
--- /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 0000000..8b13789
--- /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 0000000..ee2c34f
--- /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 0000000..dcf5c8f
--- /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 0000000..4fad761
--- /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 0000000..0fcd919
--- /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 100755
index 0000000..495db73
--- /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/mail.local.linux b/usr.sbin/sendmail/contrib/mail.local.linux
new file mode 100644
index 0000000..42d2c3c
--- /dev/null
+++ b/usr.sbin/sendmail/contrib/mail.local.linux
@@ -0,0 +1,205 @@
+From: Karl London <karl@borg.demon.co.uk>
+Message-Id: <199308111712.SAA05454@borg.demon.co.uk>
+Subject: Final port of mail.local to Linux
+To: eric@cs.berkeley.edu
+Date: Wed, 11 Aug 1993 18:12:27 +0100 (BST)
+X-Mailer: ELM [version 2.4 PL21]
+MIME-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+Content-Length: 11415
+
+Hi,
+ Sorry about this.. This is a final version of mail.local for
+linux..
+
+This is what I would like to see distributed with 8.6 if poss...
+
+Karl
+
+--------------
+
+begin 600 mail.local.linux.tar.Z
+M'YV0;<*D8>."S9LQ8=B\`,"PH<.'$"-*G$BQHL6*(&C`N`$#!@@`($#$N%'#
+M(TB1)$V&7,D2A$<0-6C,D$%3QHT8+V/HI$$#9(V+0(,*'4HT8ITY=,+("0E@
+MC5(V12<ZE0,UJM6K6+-JW<KU:L"!!0\F?`$G#!TT;L*T*3/'!9JN<*WBA*%1
+M)<J2'T..Q'NRY0P;,6:$+`DC!@V:,VK(T#MCQDV0,.)*GFP4J5*F4ZMNS4RY
+ML^?/H#^_4-%"`0@5((:\@9-'3IHS:.B`0#$FA<@<.3Q205,&A)0R9\JXH3,'
+MQ!LS(,[VKN(FC9TR<N:DH9/'./(A"=.8>2.G>1@7IE$'8<,&A&O8Q,VSA?Z<
+M#/C3X7V7(9,&J6LQ=>BD>>,&1!@W9(!P5&]I]#?'&W7(,49O_P4H1H%*5;>=
+M'&W,P0((=TR'AG%+97@6@G3$U\8;])F1!D+Z\7>A4KW!`5T;T]$Q'PAPR/&&
+M'6F0,>-99B7'&PC;D?=&AFZ<`<(8_-&7HAMSQ,<B"&O1H4-\,;@@'WWVI8'?
+MDL4=!\*!"2YX)(F]M7&4;'*4D52!/C(HQHV](<G:>;'%MY(;;^BWX(5GU0<"
+M&_7)YB62`$ZW'Y/^`=@FD&\(2:216([!AD!KR?$>:C)8^1N6=-R7WZ'%L?E@
+M6G)(R%T;4)ZI7HTDUB&F<OZ]^=R8<[Y6YVDLX:EG&7RBX2>@2%DW9J%<)AH@
+MK$$:]"@(D4Z:1J4@L*F<G2&1<5`=:PUGUJ'&OL"=<<HM%9",KB54'*LXZAB@
+MAQO"RJFG2UX*P@Q6CE=>&&0\)X=^TA4)I5G0I6$NE,(M6:"19I1A5H)L<2C@
+M'+UYV6=Q!YI!QQTL4IMJL%C",6EUR#:J[,'^C;$&GG>P,5]PV4H97@*[^<DJ
+M&:[*5J"D=>A(\7$7/ZGC<P:YZ"#(/S+G''3246?=R]@!.J%W%PH!W1IEJ%Q=
+M@]&F1VBG6N;'75OQT6"E$V5H"-VB::TE+*Q&ZYMT=7@N!6O:#7LY77%;P_NU
+MQ@%5)T9O`Q[[!@C"61M=Q$NQ.J*,--I(\QCIZ>A:>T#:B.K$7_*,<9H:LPOB
+MERZ.H=V)C>_7H6MTR-B?BQ36)QU_E\9'!1))3`'"%$\80<4504A1!`BU@P"%
+M%$]8D00111`!@A!9@##[[[X?48035-@>A!/*#_$$]5(D(4055#PAA>U@@!&$
+M[;6?<`((UQ,1W_7-%X'%\$5,8;OXP#<!!1-))`\"[U*0PO6HT+\I7"@)3A@"
+M$ZI`!`0>(6K@`X$3GD`%$/"O"4F@@O_"=Z'GQ2<)^N.?_P`H0.H5$`2Y`T$3
+MBB"%(2!A@$$00A+X1X7FM0\$1LB@$^IG.R/@+PC"ZQT!AU`%)O1.>%60`A2>
+M,(4BO,]W(&C@%!08!!`FSTK`<X($GP""(EAA>A6<P@N9P`3G(0%Z19`>]>XG
+MA=1LCPK=^U[XQK>\W_$OADQP(JY\V$;X13$)OAL"%0Z(/4`609"$',+QP!@$
+M)EQH"E`X9!(:>2'Y%2&$O<O"A?"G/2<T,0I5`.,DF1`?(@2A"4&0GNU0@$`%
+M,M"!$*S@!"MXP0QN\`D7&MX3B.B[%5(/A4:X716$,`4"4@%\OSO"$YY`A"G$
+M!W]-E(+QAE"_'5B0B?<+9A6:>"%34B$(FVRC+G-8/6OB[WM30"`/LZC!`%8!
+M"@3<7@KB@X0G7,&++$Q-$+;IOQMNCWU.:-[SQ->\%-Y1AC34Y/_.^+PV(M"-
+MW`L"(F\'QR0(,CX'G6$&%8J_.5:0E0E<8`.=<`0)II%_:J0F"MM(P3-*X0JU
+M*X)M>E<[!V81H,WC71:>&<$4/@\$_`2F&8.'.]T!L`B5_*(6DQ#,(!#!>$U4
+MGD_/*#QL>D^C-01F?*90!1=&\92I+$+L3I,`(*!@!"DHRUGHUA8T)*`&+A`,
+M"J0F!ZI9S38Q>,%(7I"#&(3G!0H8P<W8D+/>\$"M:&BK#Q006!V9R`V]^0(4
+M@C"[+S!AEU307P)$\`(ZM`$.+S`(0@B"A=*:5@0*"(UJ5_L5@HAV+*T-RVA=
+M,(;5@F8N=<G+7>RR%[NP9"0PJ$$-!B.3FMBD(XSAR0T@8]OF#N5,E_D(9[@R
+M7>=:][K8E<QH2H,KU=0*/;.IS6URX[P?_28XP^D2<MC6'+=-ISI>:IIVN.,=
+M>=G+/+9*3YH@)H?VC!4UFPH4O+B%M0%%RT`(4A"#%#6J"#&*0A;"D(8<YKG\
+MB(A$HT/1H5:4)AJ]*$8S0E>.=H2&'H7,420CE))`Y:0.1VE*N*K2E03<M6)Y
+M"4P*'I..-H8F-0FD/[`*@ZSBM)K6Y%=CNCH1KWSTJT`)2\6&XD]QL';BD?FK
+M692"CKPR->,L;0E4!P9!@TOU8%29*5AIFIFK>A/D(=/*R.A!<IZ4W*LF!VM0
+M28HRHJC\HV0-B618?M;9I,4;C5EK#-@JV+;XTZUOY8DWX@)8N=AP+ANE:T;L
+M6M2[:GPH>=&+?>3Q3[Z@PR^2C2M@`VO9H4B6L(7MUV$&EIBO=F:QS96!;ZKJ
+MV,<6Y>=EA<%D*%,9&5A6,!BK`&:S;ERK('=@G.DL<[7V61F`MIH9B8%HRVDO
+MTMZ[-++*]VD"B]K4JE:&JRGJ;L/BVI:^)B^Q2;!LX4*;6B*VWJ)I.SK<CIN\
+MUZ+>K.&-/^KV6G3X%@:_`0YB@B,<@+Z&.&4OKD6.JUEQ)'>T`)G!<DRF=<\X
+MAZN55%@V<PA=ADOWK3N@3G4>;MT<7N>&_P[5=D7=7>]^%SQ=&@]YRF.>&=&H
+MQNH!-'MOC"/XQ$<^\Z%O"NK[^?L"VL7Y^<Y^*\W?_OJG/!(.L(")%"DLEQ?!
+M65H0A+94'@=W_L$04OU_O2LA`>LGU!6V\(74BR%6;8@]'.IPG7QD7Q"E,,0B
+M'A$*25QB$Y_X.RE2T8I$P.)#)]A%I89QC&7\:?3`R$:(5E2.1*_CU_&H1]3D
+MW8\-#.0@LQCZ0XZ^E8N,NR-O%TE%4K+IE]Q?)L,)T4^&TH2-+"5853F;5FJ=
+MI+'<(BW!KD&QXU)XQ./E)<$H5*X2TYC(!($RF>E,7$&3A=.LYC6AGD)^=I.R
+MX(SZ.#,X!7.V$9WJA#H"VRF%=\;3"?/$53WO^<4V#F&?4?TY"K7HQX%*H:#!
+ME%$)=2%7P%`N=5.=!$<2-7K%U#T7A2L"N%&TYU&]%U*O1%(F=00H-3TJA3\M
+MQ4(PU40SU3WIA($/Y4<ZQ5,5-%6_$U13152Y(W.^DU33`SQ-]50Q)57!]%."
+METX(M5%:A2M<Y56FA$K2<RF`%5C:`2!E@!R`,AP*,`8EMA1R`F>QL05=``(]
+MH``B8%9HE1I%1B>R01MXA1NZ85[`43#]QEY'@V]*$U_9`6[?P05NP`6F<5]B
+M6!S[Q1[SX0)T*`([$%B%HQT@,!H@H"M_4B"RH0))*%AFP(1.J(@*8!EZ<B13
+M^"5C,`;20098J(4@T(5GE0*Q]5H$,09OY0(V,!MT95?E9ALVH%<YP%<Q`(B"
+M6"C(88B(^(2+V(B#55@@P`-SD`=S0!9*H19NL5B"Y0;.9EC!.(R4>(Q*J(R$
+MM6/`*(PO<"`FHR;0F(S+^(O-^`(FHC+;V(O4"%GZ88XO4"#C*(V^6(US8!!G
+ML([=R`-F,`;#01!H@(SD:%CF2`9B((_3:%AP<`?ND8_1.(_ZL18`V8YUT!Q(
+M49#ZR([4"!W=\08+28T/N1\7R8QT0`:`\H\&R8T!Z8U<4R0;^8F(Q59N@5J-
+MU80%4@8)8`3@QP0)D`!^-0*.]9(),$LR^4TT"0.,I8@)H".`HB\@\`62A0(H
+MH(@7(H67H0(ID`*!:`=OD",)0)%'F91+.1Q-*66RX91+H0(7X@)D&953695D
+MD`!)9@9Y\"!F@!Q("05*"9:G898*()1(P1V1I95T"952J0!4:95'$0;!D95R
+MB0*!209VJ0!?X08HH!1G,`8<=@9V,$\)H(C^(0>1&8@)T)<J`)EV$(A[H`!7
+MB0?DTA^8N1KG2`:<60:F"1W]T9>J"9F<:1\U0R-AL'($>1H#R9F8*8478@9D
+M<"'3EA"<60<Y\@6R@9RL29I]>7%OT`:!2)K5Y@;PB`(B,(IBP08B<"&7=022
+MQ4+$(P7>^03@B4HS])>D"9VHT@,25$1,P)EWX"LJ,QNTL2'N&1QTH)J/J9F2
+MF9F4>2$B0`9FH`-RH`,B$)4@$`+N602Y8YD),`<>(H7W:1NC69,(`3$@<`)D
+M<`(Z4).&*`:_M@:;$R!(\EG;(@;UR8BD69-BD"9AL`:<V9FYV1LG8`8>VJ(9
+M:J-RX*$@BAHB:C(E.B8HJA\JVALL6I.7B1PHP)X0F@`L09$HT).OEYUUP`;Z
+MX3&]T0+(H9J@DJ`SF@#LZ8FSJ9EA^J(*(Z,Z6J,;^@,Y6I..%097ZC)*.IC!
+M@0)_69-]0)J0.08@T`+NZ:4`PIF@"0(K$*APL)K3N:2S$0*?J9F5V:)V6@9X
+MNJBC09JXD@3(,::(&')E(#HF,A\78F!S,V^5$YT@H)_P6"!X&BWU=FM0BAK,
+M^2]T((5L<2&/!AT9`C&CJJ&EJC9C"BMEH9O<87$#`:NX@B1RL%]PD&?^LI^+
+MPIS@$:N`E0"SFI]JPIR52IJ$B`(A,*8F8`*-VJ08AZUTL*J.J:!\P`>8NA(A
+M@`(#Z8GZ.9!I0Z[1J:Y\0"-WT`(^,)!?,*L,*B`Y$I4M.J;N":]W(*]J,I#:
+MRIP*^@/ZRJ_^2C<@H`.?^`,82XOK&2#NF9=I8J]MD*<3,AO%61[N"0/6]*B4
+M:4TKL`*@":$E"P)\X)Y$V89-.IRG\;*MB0?3@0(E^Y=[.HG[^;%.ZIR7J`+L
+M*9JDF4-Y=!IF``><F9!EH)S)80?&R:W#`20X6S4OR9E]20=N<"%/6`9;(`-T
+M@0-=L*A@ZXGV03-P@`*215E(8%F8I3]YVJTWZXEML`9(40:?A0)@JZ`]X)XM
+M$`,RFZ_O^K2>*)S5>;,">@<KD*`$6Y-22J6K)P(-*63U":W5F1Q^VZQRX&#A
+M6`9@2IJ(B98IT)!/N`:`ZP8BFR:4&KB+>KH#*[4H8`)T8+5LD*>TJYA/ZQK#
+M809-"@<":@085P+%@;S=>:IMT)2VB[NZNY@),+9;``-9Z)XGP`4P<`*<.;(^
+M.[:>&`/69`;Z.0<H,+87(AUZ4`;'<;XOF0+IVY$%(I46VJ+=2KW6JX782X<G
+M\*1<"UGA.Z-5HZ$76I/=^K^]$:Z)"%G5>[W8:P3KH\`A(`9C\+?H^XG&BZK+
+M6P.3JZ2]FU;Y,08H<`(^<`+!"0=Y2KG@>[(SNJ<U^<&_JXC"^[0"JKQB^[XS
+MVJT)LZS<,;P=G`!H&J.<&;0)8(B:2C`K1YB]@8B0E3(OZ;FMDQ8R@K.0-2/_
+M03BF&;I6DJ3=&@(%HB-XX+Z0=2'9ZP;]"Z$?#`<A/,+\>\)Y:HA/D!]J+!MA
+M<(AEX,2094VZLF2?JS3\-@=*/&4=EA#*TH>G4:UIO,9E;,)`@L*SFY@I\):$
+M-0=HX,.^R:0[;"-RX,,PNZQ3.I,"*B.?Q1VB>ZP8@CJ]09'<4;H)D"9TD"".
+M*9Q`RU@UJR^.>XCS9IF8*9Q>>[1TH[01VBFW28E?(@:U*<S,-JP2&B`JT)M8
+M^Y4P.L47T@9B()P7X@9R<,UW@*MO>2']=;6=>8EN:085<@9;,!==<"'X809;
+M@`,J@!,R0`/IC)MGL06H-#]RFT=.D+;4^994BV@VTLU_`C%EP+KJ6<0J@*FH
+M003U0<A#PBQ<JR\@,S@->3)#TA]L]:<M`#J?*C#ET5IO@@<-@Q#]\3<*#0(E
+M!B#"%F:P`C$`TEK^`2@U6ARC.ZV'S*U,^J[Q:J[TJA8H0#=16;^4Z\D\"<J?
+M6-$H@]'S9K$VC,MKD<*N#,LH$`-Y2L0?''+`2P?"BU@U/(Q-';>5A9Y,$'K7
+MG,N+VL6T$<TSXIZ4EA1T`*]F@0878@)S(`8*&J[M&A(H4-<N@!1?8)T%L@8+
+MZIZ&NZZW\P6UPP1.L`1[_8]^/2(Z$M0@4,!26M0^V=46N[HS,KK+BUA0G:W=
+M,=55S5@(?=*[`1UE<`)39AZ_UAN0MJ4;?3&#PRH+LG(-TR=N(-C*X3>/=B1J
+M308GC2S'BD4Q4QQK\1_%(=SU2=*(^#<"`MBYW8<*7:UX2\W"J85Y;1PNXIA<
+MC4)?$`10$$G8PP=/\`5#X#N41=Y?<`7$XP1,H%!3@-CM-P52P`?QG017L$U2
+MH*`\X!)"?95$34&6B]D@T-3=;1^JO,D4B2=V69-1'=I4/<2D_<TFZQ*<:8BF
+M9;%/L-U?@@8(P@8!XM`):P:BM08G0#+*70;61-`9X0(T0$R)=].,VJ0EC@+6
+MC;.7-01+\`7RHZ"4'>!4,."?B+Q,/0>='=?QFR8\K.#+RN!0K;L!W*)GD">#
+M(Z+-F0!$#-#'@1QL3="L>^,7`@.KUT1%L./30P2\"\E8+<,H,,[EW-5`4`(@
+M_H=EO19-F2!;?K=,2FEE4-"W+.:/5`1E_@5-1`6V,;BSL>7*F0*%^]^5:]0B
+M(,J@6\HJ4^3+B^!+[K--_@8-WLI03M@S.N70:N423IKS:<I*B<V>"*-D<,OK
+MG+YIL+[MN\Z2[0/^7;#?@@);[HDH:QW(T=_8K,=+`:B'N,V^;JCNZ09W\*1X
+MJ^R>:'+30:E@+F9U@!PKX.O7+`?\[=^3W:)#O<F67:5$7N!&?B$'WBD)KND5
+MV>DU*>J#(\S*&*8NW*VJWM\PX.B>+.21_KFD3&:C:^E)GNX+SNE_">]C\*$)
+M`,,&#S`V7LTXJ^5O^>0)$>583MJ7&JNWHR:+<M%G@S5G8"-U``=8A`2!PATG
+M0LAYH,X%`M-IIC!3G''^$2(8KS!2^"\#`=%%"1UY@$57L,2#8Q!%<C;6DG$K
+MLG+8@N(E9C.O>M(<'QV^`@<.PSHPLG)@=@>H;8G_$1S'\MH8DIO^H1ZYR6@C
+M:RT'<]('8M,L:N4?VJUC\-NVT:(P+(47W?#6'+']>@?_FB/FOJ]W_P5G,+"/
+MC+IF$(S*2/>*N0,_&D7\<0*R@3'3\6`"`@=D`#!;C,B0+"EO`#&&+Y6)GP2?
+M!2BBLYS6>1!K4/FDW<44#J%KV9;:(;QN/@=GD*</[IBI'XA!FY@*L/KC;..P
+M;YE]6<[`3(FD8YO,AHU.009D(`=?P";XDOS'O"U^NLN>6+C'+`>WZ>%]F[4J
+M@`902YK$#W)\J/TAYYM9JS)N<-8YW?R6TB]?8`9J,1!Y\-^&*#5?<JQ92XCC
+M_"7LH62'F"?^8;4#07.5`=-GP'+:7H-ZYHJ_V(%K0S>PTSA;7IB+#,`!R?6D
+M9E\.,X#<3V%]"*3``.<-=B)%V(\.4,!NIZ0JFX"#="`P\TD)<G?IT%VF&WCL
+MS@*V*!>6`-1?7RL0[>_]L8'JX)ZX'[]"`U]`_5$'%S&C*%B100$^T`<`0?4W
+MUVP@^V."*`T._,`O8/[.P%E(84X0!X(NV="QI*`/F`-?8`M*N!GWZUP""%!@
+M38IMD3XU@0*"@!%`;#N$`>V2'4<$CH``:0)A3G`1+JI&`@$<N#N!E^T3&3\U
+M`?"^A`O49.K.R<TH&5CQII=P8%N=POSQOMAGJ$3")9L-+HT,[*<F-<U@G]@2
+M#F'N0NPU9`9R2)_ZJTLF``JJ+_8EO-3?Y&()`<O\=;(_&.0@728<=:VO$&(Z
+M1`@#9QE@0DL*8%+A*05PH1Y=(,1<@"PX6"SM-%I`P!;@4LPK"PV(I4"67$#I
+M"EJ.*"L5$R(P!)#201I)P*@C0:9M-,!NC4AJ1U8K=&DFQ5*+2@1CP7W9$"EM
+MPV[X!12`E,),]<'])04VT)68Q%<Z6N2,#HRELB2(^)P]]&3YT"PDA.#4!NB`
+M+KM_<T`?@K/GU!`YD]7Z`F1`4K1#[4`,2=-%!!9TK/O%0T)'!;BA-TP`%]$R
+M[(O'1+R`1$/\2R.@''K$,/`%5.);"P..;".:`8_8C*[3=^)Q`80A"D3_D!-1
+M(DTL'"Q1S\V&A+@/81;/>FL13@'LJ>Q"%:NB5;R*6#$K:L6M*!&8X5AH`C'*
+M):D,KJ@5<`MR.0F]1;>DQ;[0$F2`3B`N,Z$F<(2<(`-L@&)@+F2QN4"7I2!=
+MGD)7J"YY,3`*1LDP`LI**`*+5&-TG2*YLHK(3?P3"7KE!L@BQJ)+CD`/2`!>
+MD0TH`%3B!'#`9<R,+@`HR9`)<@6<P&6T$7E"`8S&)L!,BD`/H`'"I0:H1@02
+M>GK`"Q@5C,4%[*-?)`;F@'M@%?%H;RV6P4@<BZ-Q/(Z",3.^`-"(`Y!C13"+
+MO"4EJ$7IR!97@@VP`3>`!@R&CF`#8*,,4`RI2"0TAL?@$IPC9=B+F,$O4A?U
+M:![;HWMD"'Y(!("A[Q(;PDL9(B^G33Z@E_0@:[)-&WH;PN+;T!>!`1[B(Z@I
+M#WE(/2A`Z18?%8"!##!>YE,PF@*CH=@$CA$36&/,F`H(<R$R3<G1$"#"07(!
+M^0C9,LRB"5N9J45\F-018BS-B-EZ)J;/B(P_XR^@#)<0D?+Q2;P8'"D2-,5\
+MH#%?1LH(BPM)9';,F>DQ:P+(_`@A`R?>C!CBD7=BSNP)F`<2GTR>*19\IC?T
+M&D!3'R1%EK$4/)++0,B`4RQ$!83P=Z>"QZR*B/,JEJ2;J4)/TD!&R5U19XI#
+ME<0SQ`+,9$E&@6*N3)=T%M""T-P:.5DMKD7+.)&-9BGDJDA#+CQ:I;D1+U+"
+MG`5-`R0E9,OAD9_FON`+?5%J_,6IF33&K6"L&G_1:E[9J_D6L:;>^(F*L7$&
+MY8AD"4>26=0'CU%P>,V,]#7`9D@(&V(S'*9$?$0V,H--V@R)U#!8I:V!:-1&
+M:(@9;`-4[@V`/`XX,@$(R.X0;I;'N+$:QL+?I!N]$1T*Y*MT-V3#;,B-'T&Q
+M^F.S_(_YYEO\JKJ!'-!-WJ@Q>X-0_@N#\S!VQ.`H'`PGZEF./`%QEDWD"!B4
+M(U@E&V.9,>3EQ^%HH(ITU`C3<<I`S.KX,%0/=N!('CD[8)!1F3G`PW;8G$62
+M<P0*59D\:T3_)""A,T>*SOG(F$FG??!(/R(_Z`?W<2AF9X2DG:M3/[+.!7H@
+M7$>64)"O@T&*C_,X/A[$0(*0J2,S`PC-S"8JA(6X$!CR@[+*#2$G.P3J?)Z]
+MTW>,B#@)/$S$B1A(C&EXC`CB43Q:A/'@DU\B1AI)Y/F8:83R1)V1Z3V&#AT1
+M`G9DD@B!/,(C/P_3*3T3A38:DKR90%)/((0DDN3U6!),\G]H3R>Q/:(D]QC(
+M(A165HGON9G!Q^O4$I\Y=G2)\O$E*RB8.)]BDD&BS_1I)CSR^D@3BZ)]+@OW
+MT2;<Y*M\$]HS?LI)U$$_41-]4`_QY'Z2@#SAD?,'G]@?_--/ZLX_Z3]GA*`(
+ME0A40PB0`<HG#V5D+J!'4E$NBH$DGAREC5`@D.)*1DI)V2$:*`FDE-_A@1I*
+M")(I[(,$V903Q'12D(%\`CUE!U$5%Z0^+:8,0BJ-IP8Q%?:!@_(/"ZHJ]N.J
+M)!2M8B"'$!+X*D9(K$S,7^F%1)%`<"W;R07@@`1@`Q2H*KJ6K2@CO`";,!D;
+MI`L@`@$B""S,\F`3+D0,P`U^Y8+*!K'F`G)<(P$!.,!!/H$FX0*FP(9P`J=$
+M:SH!,W-`94M"<)!.($!XK#)Q0,-,'0-I;P`/.$@7>CNRP`2!`NG$F;B`&6KS
+M$.AH4:%0SPB4!^00!)8">W*05;1>4D.R-$0W!/*8(MT#GMA.)X!#4058!`ND
+M2`&PNN3V(RP#@%`*`:)`S+'(EQP&QQ4K'"W@.'`I4X8U<.)V(P.A0C9`*YJ'
+M!K#H4IB&&XJ%0H$?>D`50$U3`*?-D&I1QJ0JG%L=TUTY0HLZM0'H(*$`'("D
+M/\)+"<DGX?5ZS1SPE4*@/+2`I&`D6D"&T(0;`@_(TBOJ`I*`;)"B0()]6%'+
+MH0"F@,AA2XLB$T('U;9)"V01T(PNP),J@"10*-)%'9AX,.V/!3*6]B.`*!Y(
+MD3CO642[H9$H",=GH0X*`'SU&FMS-198;_@;?\\--`=_D6E:6DDR$N4C@Z$*
+M]0$>@`CXVAH_!NGUABSA+^(IQE$?O6*?%HYA6APH5A]-#H+&$*J%3QHLR\`?
+MM9>$X]=LB%J&V@)$-&4+R9"3`A$5]1\$&_CR$WYTH"8<0HK$,FH]355J30ZL
+MTI2&]4(7Y#@;**!\E+#^%2TJC4,5J74T452'CZHDRP1&56(*X-35/"1QI1Q$
+MF0@48;$_C*PZYD]15=*I63""7)C3`JE,\R-,&UV"+)7A`9PA'8#&3EV#ZV+"
+M.$@L8$5+'`B0`4&5/O'0FP=2X<!#=0^=]),>,5A1/L99TE&`_,]/S#YR.E:7
+M0OEB#QU0;0@&%J``8$7^6Y!+P4^LI30P([P$14T3%K6&QE50.BB9:&8,AOH!
+M4"@-UX1N/`*CF0.NHK9%&*SA`SP"(;JC2\XX9*($`39:Z(:8'L:CO6%.!YE*
+M_Q0K_5.O=%)^L8+A(&UI%[$#SD,+*(`J@'!R*L00I$O2K=J(A0DP$*K:T`/\
+M(6+T5.?*%I+"9S&FR)2(,JWZ05M5Z6UUI3EB4G:6SQ):$JAI,2U_ZD25!<C1
+M6V7#(BU$G@6TD"(7<%Y+2V'E=^I00APK%NI;W^L+2(?+\8"^@&D8#/D+,;6F
+MLC)-0`[ND`<<Y#'MHK=#T+$/)H`[^FH3%0D@@+#2UZ6`!S(AAM6P9!5(F-7%
+M`&+]JII0@(&U-PQ6"WNB`)ELP`$9UL)F0IB60ETK"*`=Q82@*``@`EI9QW%=
+M&DN4AJ+1[:0`D&"#>$)&`L&R.I+A]:Q>J/%Z,.VQQC\%$%)91!QU`UA4-MB!
+M&P`"P(/7$U8VXN.IA3)Z8<'#>SRS:#;-JMDURV;;K)M]LW`VSLK9.4MGZZR=
+HO;-X-L_JV3W+9_NLG_VS@#;0"MI!2V@+K:$]M(@VT2K:1<MH&^UD`$MG
+`
+end
diff --git a/usr.sbin/sendmail/contrib/mh.patch b/usr.sbin/sendmail/contrib/mh.patch
new file mode 100644
index 0000000..7b23a5b
--- /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 0000000..6db4a45
--- /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 0000000..1621a7b
--- /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 0000000..a43af6d
--- /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 0000000..a72fd03
--- /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 0000000..627d383
--- /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/Makefile b/usr.sbin/sendmail/doc/Makefile
new file mode 100644
index 0000000..fc9dc19
--- /dev/null
+++ b/usr.sbin/sendmail/doc/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+SUBDIR= op intro usenix
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/sendmail/doc/changes/Makefile b/usr.sbin/sendmail/doc/changes/Makefile
new file mode 100644
index 0000000..46447c2
--- /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 0000000..0b91ed0
--- /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/changes/changes.ps b/usr.sbin/sendmail/doc/changes/changes.ps
new file mode 100644
index 0000000..755cb57
--- /dev/null
+++ b/usr.sbin/sendmail/doc/changes/changes.ps
@@ -0,0 +1,1088 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Italic
+%%+ font Times-Bold
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 11
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Italic
+%%IncludeResource: font Times-Bold
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 14/Times-Roman@0 SF(Changes in Sendmail V)196.615 141 Q(ersion 8*)-1.554 E
+/F1 10/Times-Roman@0 SF(Eric Allman)263.42 165 Q/F2 10/Times-Italic@0 SF
+(Univer)220.2 183 Q(sity of California, Berk)-.1 E(ele)-.1 E(y)-.3 E
+(Mammoth Pr)251.98 195 Q(oject)-.45 E F1(ABSTRA)262.085 227.4 Q(CT)-.4 E -1.11
+(Ve)112 243.6 S 1.709(rsion 8 of)1.11 F F2(sendmail)4.209 E F1 1.709
+(includes a number of major changes from pre)4.209 F 1.71(vious v)-.25 F
+(ersions.)-.15 E .701(This paper gi)112 255.6 R -.15(ve)-.25 G 3.201(sav).15 G
+.701(ery short history of)194.794 255.6 R F2(sendmail)3.201 E F1 3.201(,as)C .7
+(ummary of the major dif)329.82 255.6 R(ferences)-.25 E .953(between v)112
+267.6 R .954(ersion 5 \(the last publically a)-.15 F -.25(va)-.2 G .954
+(ilable v).25 F .954(ersion\) and v)-.15 F .954(ersion 8, and some dis-)-.15 F
+(cussion of future directions.)112 279.6 Q .48
+(In 1987, the author stopped major w)97 324 R .48(ork on)-.1 F F2(sendmail)2.98
+E F1 .48(due to other time committments, only to return)2.98 F(to acti)72 336 Q
+.3 -.15(ve w)-.25 H(ork in 1991.).05 E(This paper e)5 E(xplores wh)-.15 E 2.5
+(yw)-.05 G(ork resumed and what changes ha)277 336 Q .3 -.15(ve b)-.2 H
+(een made.).15 E .58(Section 1 gi)97 352.2 R -.15(ve)-.25 G 3.08(sas).15 G .58
+(hort history of)173.36 352.2 R F2(sendmail)3.08 E F1 .58(through v)3.08 F .58
+(ersion 5 and the moti)-.15 F -.25(va)-.25 G .58(tion behind w).25 F .58
+(orking on)-.1 F -.15(ve)72 364.2 S .126(rsion 8.).15 F .126
+(Section 2 has a rather detailed description of what has changed between v)
+5.126 F .125(ersion 5 and v)-.15 F .125(ersion 8.)-.15 F
+(The paper \214nishes of)72 376.2 Q 2.5(fw)-.25 G
+(ith some thoughts about what still needs to be done.)168.95 376.2 Q/F3 10
+/Times-Bold@0 SF 2.5(1. HIST)72 400.2 R(OR)-.18 E(Y)-.35 E F1 .151
+(As discussed else)112 416.4 R .151
+(where, [Allman83a, Allman83b, Allman&Amos85] sendmail has e)-.25 F .151
+(xisted in v)-.15 F(ar)-.25 E(-)-.2 E .405(ious forms since 1980.)87 428.4 R
+.405(It w)5.405 F .405(as released under the name)-.1 F F2(delivermail)2.905 E
+F1 .404(in 4BSD and 4.1BSD, and as)2.905 F F2(send-)2.904 E(mail)87 440.4 Q F1
+(in 4.2BSD.)2.5 E(It quickly became the dominant mail system for netw)5 E(ork)
+-.1 E(ed UNIX systems.)-.1 E 1.569(Prior the release of 4.3BSD in No)112 456.6
+R -.15(ve)-.15 G 1.569(mber 1986, the author had left the Uni).15 F -.15(ve)
+-.25 G 1.57(rsity for pri).15 F -.25(va)-.25 G(te).25 E(industry)87 468.6 Q
+3.347(,b)-.65 G .847(ut continued to do some w)129.777 468.6 R .847(ork on)-.1
+F F2(sendmail)3.347 E F1 .847(with acti)3.347 F .846(vity slo)-.25 F .846
+(wly trailing of)-.25 F 3.346(fu)-.25 G .846(ntil ef)445.204 468.6 R(fecti)-.25
+E -.15(ve)-.25 G(ly).15 E .255(stopping after February 1987.)87 480.6 R .255
+(There w)5.255 F .255(as minimal support done by man)-.1 F 2.756(yp)-.15 G .256
+(eople for se)389.796 480.6 R -.15(ve)-.25 G .256(ral years, until).15 F
+(July of 1991 when the original author)87 492.6 Q 2.5(,w)-.4 G
+(ho had returned the Uni)249.36 492.6 Q -.15(ve)-.25 G(rsity).15 E 2.5(,s)-.65
+G(tarted acti)379.4 492.6 Q .3 -.15(ve w)-.25 H(ork on it ag).05 E(ain.)-.05 E
+1.271(There were se)112 508.8 R -.15(ve)-.25 G 1.271(ral reasons for rene).15 F
+1.271(wed w)-.25 F 1.271(ork on)-.1 F F2(sendmail)3.771 E F1 6.271(.T)C 1.271
+(here w)369.549 508.8 R 1.27(as a desire at Berk)-.1 F(ele)-.1 E 3.77(yt)-.15 G
+(o)499 508.8 Q(con)87 520.8 Q -.15(ve)-.4 G .097
+(rt to a subdomained structure so that indi).15 F .098
+(viduals were identi\214ed by their subdomain rather than by)-.25 F 1.758
+(their indi)87 532.8 R 1.758(vidual w)-.25 F 1.758(orkstation; although possib\
+le in the old code, there were some problems, and the)-.1 F .66(author w)87
+544.8 R .66(as the ob)-.1 F .66(vious person to address them.)-.15 F .66
+(The Computer Systems Research Group \(CSRG\), the)5.66 F 1.89
+(group that produced the Berk)87 556.8 R(ele)-.1 E 4.39(yS)-.15 G(oftw)238.12
+556.8 Q 1.89(are Distrib)-.1 F 1.89(utions, w)-.2 F 1.89(as w)-.1 F 1.89
+(orking on 4.4BSD, and w)-.1 F 1.89(anted an)-.1 F .053
+(update to the mail system.)87 568.8 R .053(Bryan Costales w)5.053 F .053(as w)
+-.1 F .053(orking on a book on)-.1 F F2(sendmail)2.553 E F1 .053(that w)2.553 F
+.053(as being re)-.1 F(vie)-.25 E(wed)-.25 E .923(by the author)87 580.8 R
+3.423(,w)-.4 G .923(hich encouraged him to mak)154.359 580.8 R 3.422(es)-.1 G
+.922(ome re)283.572 580.8 R 3.422(visions. And)-.25 F .922(the author w)3.422 F
+.922(anted to try to unify)-.1 F(some of the disparate v)87 592.8 Q(ersions of)
+-.15 E F2(sendmail)2.5 E F1(that had been permitted to proliferate.)2.5 E .023
+(During the 1987\25591 f)112 609 R(allo)-.1 E 2.523(wp)-.25 G .023(eriod, man)
+228.482 609 R 2.523(yv)-.15 G .023(endors and outside v)283.498 609 R .023
+(olunteers had produced v)-.2 F .024(ariants of)-.25 F F2(sendmail)87 621 Q F1
+5.518(.P)C .517(erhaps the best kno)136.688 621 R .517(wn is the ID)-.25 F
+3.017(Av)-.4 G .517(ersion [ID)280.317 621 R 3.017(A87]. Originally)-.4 F .517
+(intended to be a ne)3.017 F 3.017(ws)-.25 G .517(et of)485.433 621 R .268
+(con\214guration \214les, ID)87 633 R 2.768(Ae)-.4 G .269(xpanded into a f)
+189.464 633 R .269(airly lar)-.1 F .269(ge set of patches for the code.)-.18 F
+.269(Originally produced in)5.269 F .471(Sweden, ID)87 645 R 2.971(Ad)-.4 G
+-2.15 -.25(ev e)149.472 645 T .471(lopment passed to the Uni).25 F -.15(ve)-.25
+G .471(rsity of Illinois, and w).15 F .47(as widely used by the f)-.1 F .47
+(airly lar)-.1 F(ge)-.18 E .077
+(set of people who prefer to get and compile their o)87 657 R .077
+(wn source code rather than use v)-.25 F(endor)-.15 E .078(-supplied bina-)-.2
+F(ries.)87 669 Q .32 LW 76 678.6 72 678.6 DL 80 678.6 76 678.6 DL 84 678.6 80
+678.6 DL 88 678.6 84 678.6 DL 92 678.6 88 678.6 DL 96 678.6 92 678.6 DL 100
+678.6 96 678.6 DL 104 678.6 100 678.6 DL 108 678.6 104 678.6 DL 112 678.6 108
+678.6 DL 116 678.6 112 678.6 DL 120 678.6 116 678.6 DL 124 678.6 120 678.6 DL
+128 678.6 124 678.6 DL 132 678.6 128 678.6 DL 136 678.6 132 678.6 DL 140 678.6
+136 678.6 DL 144 678.6 140 678.6 DL 148 678.6 144 678.6 DL 152 678.6 148 678.6
+DL 156 678.6 152 678.6 DL 160 678.6 156 678.6 DL 164 678.6 160 678.6 DL 168
+678.6 164 678.6 DL 172 678.6 168 678.6 DL 176 678.6 172 678.6 DL 180 678.6 176
+678.6 DL 184 678.6 180 678.6 DL 188 678.6 184 678.6 DL 192 678.6 188 678.6 DL
+196 678.6 192 678.6 DL 200 678.6 196 678.6 DL 204 678.6 200 678.6 DL 208 678.6
+204 678.6 DL 212 678.6 208 678.6 DL 216 678.6 212 678.6 DL/F4 8/Times-Roman@0
+SF .045(*An earlier v)93.6 690.6 R .045(ersion of this paper w)-.12 F .044
+(as printed in the Proceedings of the 1994 A)-.08 F .044
+(UUG Queensland Summer T)-.44 F .044(echnical Conference,)-.56 F(Gate)72 700.2
+Q -.08(wa)-.2 G 2(yH).08 G(otel, Brisbane, March 1994.)107.928 700.2 Q F3
+(Changes in Sendmail V)72 756 Q(ersion 8)-1 E(1)499 756 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 294.65(2C)72 60 S(hanges in Sendmail V)378.87 60 Q
+(ersion 8)-1 E/F1 10/Times-Roman@0 SF .151
+(In about the same time frame, attempts were made to clean up and e)112 96 R
+.151(xtend the Simple Mail T)-.15 F(rans-)-.35 E .468
+(port Protocol \(SMTP\) [RFC821].)87 108 R .468(This in)5.468 F -.2(vo)-.4 G
+(lv).2 E .469(ed clari\214cations of some ambiguities in the protocol, and)-.15
+F .085(correction of some problem areas [RFC1123], as well as e)87 120 R .084
+(xtensions for additional functionality \(dubbed)-.15 F 1.052
+(Extended Simple Mail T)87 132 R 1.053
+(ransport Protocol, or ESMTP\) [RFC1425, RFC1426, RFC1427] and a richer)-.35 F
+1.376(set of semantics in the body of messages \(the Multipurpose Internet Mai\
+l Extensions, a.k.a. MIME\))87 144 R .497([RFC1521, RFC1344].)87 156 R .497
+(Neither the ID)5.497 F 2.998(Ag)-.4 G .498(roup nor most v)258.526 156 R .498
+(endors were modifying)-.15 F/F2 10/Times-Italic@0 SF(sendmail)2.998 E F1 .498
+(to conform)2.998 F 1.7(to these ne)87 168 R 4.2(ws)-.25 G 4.2(tandards. It)
+148.23 168 R 1.699(seemed clear that these were `)4.2 F 1.699(`good things')
+-.74 F 4.199('t)-.74 G 1.699(hat should be encouraged.)394.483 168 R(Ho)87 180
+Q(we)-.25 E -.15(ve)-.25 G 1.635 -.4(r, s).15 H .835(ince no one w).4 F .835
+(as w)-.1 F .835(orking on a publically a)-.1 F -.25(va)-.2 G .835(ilable v).25
+F .836(ersion of)-.15 F F2(sendmail)3.336 E F1 .836(with these updates,)3.336 F
+(the)87 192 Q 2.5(yw)-.15 G(ere unlik)113.79 192 Q(ely to be widely deplo)-.1 E
+(yed an)-.1 E 2.5(yt)-.15 G(ime in the near future.)274.25 192 Q .466
+(There are, of course, other mail transport agents a)112 208.2 R -.25(va)-.2 G
+.465(ilable, such as).25 F F2 .465(MMDF zmailer smail)2.965 F F1(and)2.965 E F2
+(PP)2.965 E F1(Ho)87 220.2 Q(we)-.25 E -.15(ve)-.25 G .842 -.4(r, n).15 H .042
+(one of these seemed to be g).4 F .043(aining the prominence of)-.05 F F2
+(sendmail)2.543 E F1 2.543(;i)C 2.543(ta)390.518 220.2 S .043
+(ppeared that most compa-)400.281 220.2 R .238(nies w)87 232.2 R .238
+(ould not con)-.1 F -.15(ve)-.4 G .238(rt to another mail transport agent an)
+.15 F 2.737(yt)-.15 G .237(ime in the forseeable future.)327.438 232.2 R(Ho)
+5.237 E(we)-.25 E -.15(ve)-.25 G 1.037 -.4(r, t).15 H(he).4 E(y)-.15 E
+(might be persuaded to con)87 244.2 Q -.15(ve)-.4 G(rt to a ne).15 E(wer v)-.25
+E(ersion of)-.15 E F2(sendmail)2.5 E F1(.)A .841(All of these con)112 260.4 R
+.841(vinced the author to w)-.4 F .841(ork on a updated v)-.1 F .841(ersion of)
+-.15 F F2(sendmail)3.342 E F1 .842(for public distrib)3.342 F(u-)-.2 E(tion.)87
+272.4 Q 1.024(The ne)112 288.6 R 3.524(wv)-.25 G 1.023(ersion of)155.858 288.6
+R F2(sendmail)3.523 E F1 1.023(is referred to as v)3.523 F 1.023
+(ersion eight \(V8\).)-.15 F -1.11(Ve)6.023 G 1.023(rsions six and se)1.11 F
+-.15(ve)-.25 G 3.523(nw).15 G(ere)491.79 288.6 Q 1.281
+(skipped because of an agreement that all \214les in 4.4BSD w)87 300.6 R 1.281
+(ould be numbered as \2318.1\232.)-.1 F 1.282(Rather than)6.282 F(ha)87 312.6 Q
+2.05 -.15(ve a)-.2 H 4.25(ne).15 G 1.75(xternal v)127.76 312.6 R 1.75
+(ersion number that dif)-.15 F 1.75(fered from the \214le v)-.25 F 1.75
+(ersion numbers,)-.15 F F2(sendmail)4.25 E F1 1.75(just jumped)4.25 F
+(directly to V8.)87 324.6 Q F0 2.5(2. CHANGES)72 348.6 R(IN VERSION EIGHT)2.5 E
+F1 .138(The follo)112 364.8 R .139
+(wing is a summary of the changes between the last commonly a)-.25 F -.25(va)
+-.2 G .139(ilable v).25 F .139(ersion of send-)-.15 F(mail from Berk)87 376.8 Q
+(ele)-.1 E 2.5(y\()-.15 G(5.67\) and the latest v)170.9 376.8 Q
+(ersion \(8.6.6\).)-.15 E(Man)112 393 Q 2.5(yo)-.15 G 2.5(ft)142.68 393 S
+(hese are ideas that had been tried in ID)151.29 393 Q(A, b)-.4 E(ut man)-.2 E
+2.5(yo)-.15 G 2.5(ft)363.27 393 S(hem were generalized in V8.)371.88 393 Q F0
+2.5(2.1. P)87 417 R(erf)-.2 E(ormance Enhancements)-.25 E F1 .549
+(Instead of closing SMTP connections immediately)127 433.2 R 3.049(,o)-.65 G
+.549(pen connections are cached for possible)342.135 433.2 R .029(future use.)
+102 445.2 R .029(There is a limit to the number of simultaneous open connectio\
+ns and the idle time of an)5.029 F(y)-.15 E(indi)102 457.2 Q
+(vidual connection.)-.25 E 1.219(This is of best help during queue processing \
+\(since there is the potential of man)127 473.4 R 3.719(yd)-.15 G(if)474.82
+473.4 Q(ferent)-.25 E 1.113(messages going to one site\), although it can also\
+ help when processing MX records which aren')102 485.4 R(t)-.18 E
+(handled by MX Piggybacking.)102 497.4 Q 1.258(If tw)127 513.6 R 3.757(oh)-.1 G
+1.257(osts with dif)161.075 513.6 R 1.257
+(ferent names in a single message happen to ha)-.25 F 1.557 -.15(ve t)-.2 H
+1.257(he same set of MX).15 F .94(hosts, the)102 525.6 R 3.44(yc)-.15 G .94
+(an be sent in the same transaction.)153.45 525.6 R -1.11(Ve)5.94 G .94
+(rsion 8 notices this and tries to batch the mes-)1.11 F(sages.)102 537.6 Q
+-.15(Fo)127 553.8 S 3.638(re).15 G 1.138(xample, if tw)148.668 553.8 R 3.637
+(os)-.1 G 1.137(ites `)216.42 553.8 R(`foo.com')-.74 E 3.637('a)-.74 G 1.137
+(nd `)286.914 553.8 R(`bar)-.74 E(.com')-.55 E 3.637('a)-.74 G 1.137
+(re both serv)352.408 553.8 R 1.137(ed by UUNET)-.15 F 3.637(,t)-.74 G(he)
+470.513 553.8 Q 3.637(yw)-.15 G(ill)495.66 553.8 Q(ha)102 565.8 Q .557 -.15
+(ve t)-.2 H .257(he same set of MX hosts and will be sent in one transaction.)
+.15 F .258(UUNET will then split the mes-)5.258 F(sage and send it to the tw)
+102 577.8 Q 2.5(oi)-.1 G(ndi)213.28 577.8 Q(vidual hosts.)-.25 E F0 2.5
+(2.2. RFC)87 601.8 R(1123 Changes)2.5 E F1 2.607(An)127 618 S .107
+(umber of changes ha)141.827 618 R .407 -.15(ve b)-.2 H .106(een made to mak)
+.15 F 2.606(es)-.1 G .106(endmail `)321.07 618 R .106
+(`conditionally compliant')-.74 F 2.606('\()-.74 G .106(that is, it)469.058 618
+R(satis\214es all of the MUST clauses and most b)102 630 Q
+(ut not all of the SHOULD clauses in RFC 1123\).)-.2 E
+(The major areas of change are \(numbers are RFC 1123 section numbers\):)127
+646.2 Q 26.5(\2475.2.7 Response)102 662.4 R .565(to RCPT command is f)3.065 F
+3.065(ast. Pre)-.1 F(viously)-.25 E 3.065(,s)-.65 G .565(endmail e)362.295
+662.4 R .565(xpanded all aliases as f)-.15 F(ar)-.1 E .686
+(as it could \212 this could tak)156 674.4 R 3.186(eav)-.1 G .685
+(ery long time, particularly if there were name serv)290.118 674.4 R(er)-.15 E
+3.891(delays. V)156 686.4 R 1.391(ersion 8 only checks for the e)-1.11 F 1.392
+(xistence of an alias and does the e)-.15 F(xpansion)-.15 E(later)156 698.4 Q
+5.176(.I)-.55 G 2.676(td)184.226 698.4 S .176
+(oes still do a DNS lookup if there is an e)194.682 698.4 R .175
+(xplicit host name in the RCPT com-)-.15 F(mand, b)156 710.4 Q
+(ut this time is bounded.)-.2 E EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Changes in Sendmail V)72 60 Q(ersion 8)-1 E(3)499 60 Q
+/F1 10/Times-Roman@0 SF 26.5(\2475.2.8 Numeric)102 96 R .612
+(IP addresses are logged in Recei)3.112 F -.15(ve)-.25 G .613(d: lines.).15 F
+.613(This helps tracing spoofed mes-)5.613 F(sages.)156 108 Q 21.5
+(\2475.2.17 Self)102 124.2 R .127(domain literal is properly handled.)2.627 F
+(Pre)5.126 E(viously)-.25 E 2.626(,i)-.65 G 2.626(fs)368.196 124.2 S .126
+(omeone sent to user@[1.2.3.4],)378.042 124.2 R .12
+(where 1.2.3.4 is your IP address, the mail w)156 136.2 R .12
+(ould probably be rejected with a `)-.1 F(`con\214gu-)-.74 E(ration error')156
+148.2 Q 2.5('. V)-.74 F(ersion 8 can handle these addresses.)-1.11 E 26.5
+(\2475.3.2 Better)102 164.4 R 1.189(control o)3.69 F -.15(ve)-.15 G 3.689(ri)
+.15 G(ndi)240.088 164.4 Q 1.189(vidual timeouts.)-.25 F 1.189
+(RFC 821 speci\214ed no timeouts.)6.189 F 1.189(Older v)6.189 F(er)-.15 E(-)-.2
+E .002(sions of sendmail had a single timeout, typically set to tw)156 176.4 R
+2.502(oh)-.1 G 2.502(ours. V)398.142 176.4 R .002(ersion 8 allo)-1.11 F .002
+(ws the)-.25 F(con\214guration \214le to set timeouts for v)156 188.4 Q
+(arious SMTP commands indi)-.25 E(vidually)-.25 E(.)-.65 E 26.5
+(\2475.3.3 Error)102 204.6 R 1.06(messages are sent as From:<>.)3.56 F 1.059
+(This w)6.059 F 1.059(as ur)-.1 F 1.059(ged by RFC 821 and reiterated by)-.18 F
+.237(RFC 1123, b)156 216.6 R .237(ut older v)-.2 F .237(ersions of sendmail ne)
+-.15 F -.15(ve)-.25 G 2.737(rr).15 G .237(eally did it properly)355.186 216.6 R
+5.237(.V)-.65 G .238(ersion 8 does.)448.254 216.6 R(Ho)156 228.6 Q(we)-.25 E
+-.15(ve)-.25 G 1.934 -.4(r, s).15 H 1.134
+(ome systems cannot handle this perfectly le).4 F -.05(ga)-.15 G 3.633(la).05 G
+1.133(ddress; if necessary)402.941 228.6 R 3.633(,y)-.65 G(ou)494 228.6 Q
+(can create a special mailer that uses the `g' \215ag to disable this.)156
+240.6 Q 26.5(\2475.3.3 Error)102 256.8 R 3.212(messages are ne)5.712 F -.15(ve)
+-.25 G 5.712(rs).15 G 3.212(ent to <>.)275.628 256.8 R(Pre)8.213 E(viously)-.25
+E 5.713(,s)-.65 G 3.213(endmail w)383.028 256.8 R 3.213(as happ)-.1 F 5.713(yt)
+-.1 G 5.713(os)474.957 256.8 S(end)489.56 256.8 Q 6
+(responses-to-responses which sometimes resulted in responses-to-responses-to-)
+156 268.8 R(responses which resulted in ....)156 280.8 Q(you get the idea.)5 E
+26.5(\2475.3.3 Route-addrs)102 297 R .111(\(the ugly `)2.611 F
+(`<@hosta,@hostb:user@hostc>')-.74 E 2.611('s)-.74 G .111(yntax\) are pruned.)
+389.124 297 R .112(RFC 821)5.112 F(ur)156 309 Q 1.001
+(ged the use of this bletcherous syntax.)-.18 F 1
+(RFC 1123 has seen the light and of)6.001 F(\214cially)-.25 E 1.124
+(deprecates them, further ur)156 321 R 1.125(ging that you eliminate all b)-.18
+F 1.125(ut `)-.2 F(`user@hostc')-.74 E 3.625('s)-.74 G 1.125(hould you)462.595
+321 R(recei)156 333 Q 1.698 -.15(ve o)-.25 H 1.398(ne of these things.).15 F
+-1.11(Ve)6.398 G 1.398(rsion 8 is slightly more generous than the standards)
+1.11 F .753(suggest; instead of stripping of)156 345 R 3.253(fa)-.25 G .753
+(ll the route addressees, it only strips hosts of)293.115 345 R 3.254(fu)-.25 G
+3.254(pt)487.966 345 S(o)499 345 Q 1.29(the one before the last one kno)156 357
+R 1.289(wn to DNS, thus allo)-.25 F 1.289(wing you to ha)-.25 F 1.589 -.15
+(ve p)-.2 H(seudo-hosts).15 E(such as foo.BITNET)156 369 Q 5(.T)-.74 G
+(he `R' option will turn this of)251.91 369 Q(f.)-.25 E
+(The areas in which sendmail is not `)102 385.2 Q(`unconditionally compliant')
+-.74 E 2.5('a)-.74 G(re:)367.43 385.2 Q 26.5(\2475.2.6 Sendmail)102 401.4 R
+(does do header munging.)2.5 E 21.5(\2475.2.10 Sendmail)102 417.6 R(doesn')3.2
+E 3.2(ta)-.18 G -.1(lwa)233.88 417.6 S .7(ys use the e).1 F .701
+(xact SMTP message te)-.15 F .701(xt from RFC 821.)-.15 F .701(This is a)5.701
+F(rather silly requirement.)156 429.6 Q 19(\2475.3.1.1 Sendmail)102 445.8 R
+(doesn')3.512 E 3.512(tg)-.18 G 1.012
+(uarantee only one connect for each host on queue runs.)235.064 445.8 R
+(Connec-)6.011 E(tion caching gi)156 457.8 Q -.15(ve)-.25 G 2.5(sy).15 G
+(ou most of this, b)235.87 457.8 Q(ut it does not pro)-.2 E(vide a guarantee.)
+-.15 E 19(\2475.3.1.1 Sendmail)102 474 R(doesn')2.843 E 2.843(ta)-.18 G -.1
+(lwa)233.166 474 S .343(ys pro).1 F .343(vide an adequate limit on concurrenc)
+-.15 F 4.144 -.65(y. T)-.15 H .344(hat is, there can).65 F .757(be se)156 486 R
+-.15(ve)-.25 G .757(ral independent sendmails running at once.).15 F .757
+(My feeling is that doing an abso-)5.757 F 1.047(lute limit w)156 498 R 1.047
+(ould be a mistak)-.1 F 3.547(e\()-.1 G 1.048(it might result in lost mail\).)
+284.302 498 R(Ho)6.048 E(we)-.25 E -.15(ve)-.25 G 1.848 -.4(r, i).15 H 3.548
+(fy).4 G 1.048(ou use the)461.354 498 R .801(XLA contrib)156 510 R .801
+(uted softw)-.2 F .801(are, most of this will be guaranteed \(b)-.1 F .801
+(ut I don')-.2 F 3.3(tg)-.18 G .8(uarantee the)454.61 510 R(guarantee\).)156
+522 Q F0 2.5(2.3. Extended)87 546 R(SMTP Support)2.5 E F1 -1.11(Ve)127 562.2 S
+.154(rsion 8 includes both sending and recei)1.11 F .155
+(ving support for Extended SMTP support as de\214ned)-.25 F .229(by RFC 1425 \
+\(basic\) and RFC 1427 \(SIZE\); and limited support for RFC 1426 \(BOD)102
+574.2 R 2.729(Y\). The)-.55 F(body)2.729 E .275(support is minimal because the\
+ \2318BITMIME\232 body type is not currently adv)102 586.2 R 2.776
+(ertised. Although)-.15 F(such)2.776 E 3.076(ab)102 598.2 S .576
+(ody type will be accepted, it will not be correctly con)114.516 598.2 R -.15
+(ve)-.4 G .576(rted to 7 bits if speaking to a non-8-bit-).15 F(MIME a)102
+610.2 Q -.1(wa)-.15 G(re SMTP serv).1 E(er)-.15 E(.)-.55 E/F2 10/Times-Italic@0
+SF(Sendmail)127 626.4 Q F1 .287(tries to speak ESMTP if you ha)2.787 F .588
+-.15(ve t)-.2 H .288(he `a' \215ag set in the \215ags for the mailer descrip-)
+.15 F(tor)102 638.4 Q 3.322(,o)-.4 G 3.322(ri)123.532 638.4 S 3.322(ft)132.964
+638.4 S .822(he other end adv)142.396 638.4 R .822(ertises the f)-.15 F .822
+(act that it speaks ESMTP)-.1 F 5.822(.T)-1.11 G .821
+(his is a non-standard adv)376.446 638.4 R(ertise-)-.15 E(ment:)102 650.4 Q F2
+(sendmail)2.98 E F1 .48(announces \231ESMTP spok)2.98 F .48
+(en here\232 during the initial connection message, and client)-.1 F .587
+(sendmails search for this message.)102 662.4 R .586
+(This creates some problems for some PC-based mailers, which)5.586 F
+(do not understand tw)102 674.4 Q
+(o-line greeting messages as required by RFC 821.)-.1 E EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 294.65(4C)72 60 S(hanges in Sendmail V)378.87 60 Q
+(ersion 8)-1 E 2.5(2.4. Eight-Bit)87 96 R(Clean)2.5 E/F1 10/Times-Roman@0 SF
+(Pre)127 112.2 Q 1.263(vious v)-.25 F 1.263
+(ersions of sendmail used the 0200 bit for quoting.)-.15 F 1.264(This v)6.264 F
+1.264(ersion a)-.15 F -.2(vo)-.2 G 1.264(ids that use.).2 F(Ho)102 124.2 Q(we)
+-.25 E -.15(ve)-.25 G 1.119 -.4(r, y).15 H .318
+(ou can set option `7' to get se).4 F -.15(ve)-.25 G 2.818(nb).15 G .318
+(it stripping for compatibility with RFC 821, which is)290.046 124.2 R 2.5(a7)
+102 136.2 S(-bit protocol.)113.94 136.2 Q(This option says `)5 E
+(`strip to 7 bits on input')-.74 E('.)-.74 E(Indi)127 152.4 Q .375
+(vidual mailers can still produce se)-.25 F -.15(ve)-.25 G 2.875(nb).15 G .376
+(it out put using the `7' mailer \215ag.)303.02 152.4 R .376(This \215ag says)
+5.376 F -.74(``)102 164.4 S(strip to 7 bits on output').74 E('.)-.74 E F0 2.5
+(2.5. User)87 188.4 R(Database)2.5 E F1 1.926
+(The User Database \(UDB\) is an as-yet e)127 204.6 R 1.926
+(xperimental attempt to pro)-.15 F 1.925(vide uni\214ed lar)-.15 F(ge-site)-.18
+E .396(name support.)102 216.6 R 1.996 -.8(We a)5.396 H .396
+(re installing it at Berk).8 F(ele)-.1 E .396(y; future v)-.15 F .396
+(ersions may sho)-.15 F 2.897(ws)-.25 G .397(igni\214cant modi\214cations.)
+406.373 216.6 R(Brie\215y)102 228.6 Q 3.583(,U)-.65 G 1.083
+(DB contains a database that is intended to contain all the per)142.433 228.6 R
+1.082(-user information for your)-.2 F -.1(wo)102 240.6 S .172
+(rkgroup, such as people').1 F 2.673(sf)-.55 G .173
+(ull names, their .plan information, their outgoing mail name, and their)222.29
+240.6 R(mail drop.)102 252.6 Q .438(The user database allo)127 268.8 R .438
+(ws you to map both incoming and outgoing addresses, much lik)-.25 F 2.937(eI)
+-.1 G -.4(DA)487.46 268.8 S(.).4 E(Ho)102 280.8 Q(we)-.25 E -.15(ve)-.25 G
+1.799 -.4(r, t).15 H .999(he interf).4 F .999(ace is still better with ID)-.1 F
+.999(A; in particular)-.4 F 3.499(,t)-.4 G 1
+(he alias \214le with incoming/outgoing)355.55 280.8 R(marks pro)102 292.8 Q
+(vides better locality of information.)-.15 E F0 2.5(2.6. Impr)87 316.8 R -.1
+(ove)-.18 G 2.5(dB).1 G(IND Support)158.01 316.8 Q F1 .262
+(The BIND support, particularly for MX records, had a number of anno)127 333 R
+.261(ying `)-.1 F(`features')-.74 E 2.761('w)-.74 G(hich)486.78 333 Q(ha)102
+345 Q 1.212 -.15(ve b)-.2 H .912(een remo).15 F -.15(ve)-.15 G 3.412(di).15 G
+3.412(nt)187.116 345 S .912(his release.)198.308 345 R .912(In particular)5.912
+F 3.412(,t)-.4 G .912(hese more tightly bind \(pun intended\) the name)307.916
+345 R(serv)102 357 Q(er to sendmail, so that the name serv)-.15 E
+(er resolution rules are incorporated directly into sendmail.)-.15 E .688
+(The major change has been that the $[ ... $] operator didn')127 373.2 R 3.188
+(tf)-.18 G .688(ully qualify names that were in)376.41 373.2 R
+(DNS as A or MX records.)102 385.2 Q -1.11(Ve)5 G
+(rsion 8 does this quali\214cation.)1.11 E .429(This has pro)127 401.4 R -.15
+(ve)-.15 G 2.929(nt).15 G 2.929(ob)197.147 401.4 S 2.929(ea)210.076 401.4 S
+2.929(na)221.885 401.4 S(nno)234.254 401.4 Q .43
+(yance in Sun shops, who often still run without BIND support.)-.1 F(Ho)102
+413.4 Q(we)-.25 E -.15(ve)-.25 G 1.001 -.4(r, i).15 H 2.701(ti).4 G 2.701(sr)
+153.842 413.4 S .201
+(eally critical that this be supported, since MX records are mandatory)163.763
+413.4 R 5.2(.I)-.65 G 2.7(nS)450.26 413.4 S .2(unOS you)463.52 413.4 R .101
+(can choose either MX support or NIS support, b)102 425.4 R .101(ut not both.)
+-.2 F .101(This is \214x)5.101 F .101(ed in Solaris, and some)-.15 F/F2 10
+/Times-Italic@0 SF(send-)2.602 E(mail)102 437.4 Q F1(support to allo)2.5 E 2.5
+(wt)-.25 G(his in SunOS should be forthcoming in a future release.)192.31 437.4
+Q F0 2.5(2.7. K)87 461.4 R(ey)-.25 E(ed Files)-.1 E F1 .242(Generalized k)127
+477.6 R -.15(ey)-.1 G .242(ed \214les is an idea tak).15 F .241
+(en directly from ID)-.1 F 2.741(As)-.4 G .241
+(endmail \(albeit with a completely)368.606 477.6 R(dif)102 489.6 Q
+(ferent implementation\).)-.25 E(The)5 E 2.5(yc)-.15 G(an be useful on lar)
+239.63 489.6 Q(ge sites.)-.18 E -1.11(Ve)127 505.8 S
+(rsion 8 includes the follo)1.11 E(wing b)-.25 E(uilt-in map classes:)-.2 E
+33.72(dbm Support)102 522 R(for the ndbm\(3\) library)2.5 E(.)-.65 E 33.17
+(hash Support)102 538.2 R 1.229(for the `)3.729 F(`Hash')-.74 E 3.729('t)-.74 G
+1.229(ype from the ne)261.636 538.2 R 3.729(wB)-.25 G(erk)345.732 538.2 Q(ele)
+-.1 E 3.729(yd)-.15 G 1.229(b\(3\) library)383.641 538.2 R 6.23(.t)-.65 G 1.23
+(his library pro-)441.55 538.2 R 4.094(vides substantially better database sup\
+port than ndbm\(3\), including in-memory)156 550.2 R
+(caching, arbitrarily long k)156 562.2 Q -.15(ey)-.1 G 2.5(sa).15 G(nd v)279.89
+562.2 Q(alues, and better disk utilization.)-.25 E 31.51(btree Support)102
+578.4 R .547(for the `)3.047 F(`B-T)-.74 E(ree')-.35 E 3.047('t)-.74 G .547
+(ype from the ne)266.328 578.4 R 3.048(wB)-.25 G(erk)347.698 578.4 Q(ele)-.1 E
+3.048(yd)-.15 G .548(b\(3\) library)384.926 578.4 R 5.548(.B)-.65 G(-T)445.362
+578.4 Q .548(rees pro)-.35 F(vide)-.15 E .521(better clustering than Hashed \
+\214les if you are fetching lots of records that ha)156 590.4 R .821 -.15(ve s)
+-.2 H(imilar).15 E -.1(ke)156 602.4 S(ys, such as searching a dictionary for w)
+-.05 E(ords be)-.1 E(ginning with `)-.15 E(`detr')-.74 E('.)-.74 E 39.83
+(nis Support)102 618.6 R(for NIS \(a.k.a. YP\) maps.)2.5 E
+(NIS+ is not supported in this v)5 E(ersion.)-.15 E 34.83(host Support)102
+634.8 R(for DNS lookups.)2.5 E 19.84(dequote A)102 651 R -.74(``)2.642 G
+(pseudo-map').74 E 2.642('\()-.74 G .142(that is, once that does not ha)232.554
+651 R .442 -.15(ve a)-.2 H .442 -.15(ny ex).15 H .142(ternal data\) that allo)
+.15 F .142(ws a con-)-.25 F .099
+(\214guration \214le to break apart a quoted string in the address.)156 663 R
+.098(This is necessary primarily)5.098 F .726
+(for DECnet addresses, which often ha)156 675 R 1.026 -.15(ve q)-.2 H .726
+(uoted addresses that need to be unwrapped).15 F(on g)156 687 Q(ate)-.05 E -.1
+(wa)-.25 G(ys.).1 E EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Changes in Sendmail V)72 60 Q(ersion 8)-1 E(5)499 60 Q
+2.5(2.8. Multi-W)87 96 R(ord Classes & Macr)-.75 E(os in Classes)-.18 E/F1 10
+/Times-Roman@0 SF(Classes can no)127 112.2 Q 2.5(wb)-.25 G 2.5(em)200.35 112.2
+S(ultiple w)215.07 112.2 Q 2.5(ords. F)-.1 F(or e)-.15 E(xample,)-.15 E
+(CShofmann.CS.Berk)142 128.4 Q(ele)-.1 E -.65(y.)-.15 G(EDU).65 E(allo)102
+144.6 Q 2.395(ws you to match the entire string `)-.25 F(`hofmann.CS.Berk)-.74
+E(ele)-.1 E -.65(y.)-.15 G(EDU').65 E 4.894('u)-.74 G 2.394
+(sing the single construct)399.878 144.6 R -.74(``)102 156.6 S($=S').74 E('.)
+-.74 E(Class de\214nitions are no)127 172.8 Q 2.5(wa)-.25 G(llo)234.52 172.8 Q
+(wed to include macros \212 for e)-.25 E(xample:)-.15 E(Cw$k)142 189 Q(is le)
+102 205.2 Q -.05(ga)-.15 G(l.).05 E F0 2.5(2.9. IDENT)87 229.2 R(Pr)2.5 E
+(otocol Support)-.18 E F1 .633
+(The IDENT protocol as de\214ned in RFC 1413 [RFC1413] is supported.)127 245.4
+R(Ho)5.633 E(we)-.25 E -.15(ve)-.25 G 1.433 -.4(r, m).15 H(an).4 E 3.134(ys)
+-.15 G(ys-)491.78 245.4 Q .909(tems ha)102 257.4 R 1.209 -.15(ve a T)-.2 H .909
+(CP/IP b).15 F .908
+(ug that renders this useless, and the feature must be turned of)-.2 F 3.408
+(f. Roughly)-.25 F 3.408(,i)-.65 G(f)500.67 257.4 Q 8.538
+(one of these system recei)102 269.4 R -.15(ve)-.25 G 11.038(sa\231).15 G 8.539
+(No route to host\232 message \(ICMP message)280.568 269.4 R(ICMP_UNREA)102
+281.4 Q .829(CH_HOST\) on)-.4 F/F2 10/Times-Italic@0 SF(any)3.329 E F1 .828
+(connection, all connections to that host are closed.)3.329 F .828
+(Some \214re-)5.828 F -.1(wa)102 293.4 S .087
+(lls return this error if you try to connect to the IDENT port, so you can').1
+F 2.587(tr)-.18 G(ecei)408.889 293.4 Q .387 -.15(ve e)-.25 H .087
+(mail from these).15 F 1.712(hosts on these systems.)102 305.4 R(It')6.712 E
+4.212(sp)-.55 G 1.712(ossible that if the \214re)228.62 305.4 R -.1(wa)-.25 G
+1.712(ll used a more speci\214c message \(such as).1 F(ICMP_UNREA)102 317.4 Q
+(CH_PR)-.4 E -1.88 -.4(OT O)-.4 H 72.325(COL, ICMP_UNREA).4 F(CH_POR)-.4 E
+74.825(To)-.6 G(r)500.67 317.4 Q(ICMP_UNREA)102 329.4 Q(CH_NET_PR)-.4 E
+(OHIB\) it w)-.4 E(ould w)-.1 E(ork, b)-.1 E(ut this hasn')-.2 E 2.5(tb)-.18 G
+(een v)375.62 329.4 Q(eri\214ed.)-.15 E .678(IDENT protocol support cannot be \
+used on 4.3BSD, Apollo DomainOS, Apple A/UX, Con-)127 345.6 R -.15(vex)102
+357.6 S 1.405(OS, Data General DG/UX, HP-UX, Sequent Dynix, or Ultrix.).15 F
+1.405(It seems to w)6.405 F 1.405(ork on 4.4BSD,)-.1 F
+(IBM AIX 3.x, OSF/1, SGI IRIX, Solaris, and SunOS.)102 369.6 Q F0 2.5
+(2.10. Separate)87 393.6 R(En)2.5 E -.1(ve)-.4 G(lope/Header Pr).1 E(ocessing)
+-.18 E F1 .854(Since the From: line is passed in separately from the en)127
+409.8 R -.15(ve)-.4 G .854(lope sender).15 F 3.354(,t)-.4 G .854(hese ha)
+420.978 409.8 R 1.154 -.15(ve b)-.2 H .854(oth been).15 F .427
+(made visible; the $g macro is set to the en)102 421.8 R -.15(ve)-.4 G .428
+(lope sender during processing of mailer ar).15 F .428(gument v)-.18 F(ec-)-.15
+E(tors and the header sender during processing of headers.)102 433.8 Q .085
+(It is also possible to specify separate per)127 450 R .085(-mailer en)-.2 F
+-.15(ve)-.4 G .084(lope and header processing.).15 F .084(The Sender)5.084 F(-)
+-.2 E -.55(RW)102 462 S 1.085(Set and RecipientR).55 F 1.085(Wset ar)-.55 F
+1.085(guments for mailers can be speci\214ed as `)-.18 F(`en)-.74 E -.15(ve)-.4
+G(lope/header').15 E 3.585('t)-.74 G 3.585(og)478.595 462 S -2.15 -.25(iv e)
+492.18 462 T(dif)102 474 Q(ferent re)-.25 E(writings for en)-.25 E -.15(ve)-.4
+G(lope v).15 E(ersus header addresses.)-.15 E F0 2.5(2.11. Owner)87 498 R
+(-List Pr)-.37 E(opagates to En)-.18 E -.1(ve)-.4 G(lope).1 E F1 1.168
+(When an alias has an associated o)127 514.2 R(wner)-.25 E 1.168
+(-list name, that alias is used to change the en)-.2 F -.15(ve)-.4 G(lope).15 E
+(sender address.)102 526.2 Q(This will cause do)5 E
+(wnstream errors to be returned to that o)-.25 E(wner)-.25 E(.)-.55 E 1.813
+(Some people \214nd this confusing because the en)127 542.4 R -.15(ve)-.4 G
+1.813(lope sender is what appears in the \214rst).15 F -.74(``)102 554.4 S
+(From_').74 E 3.127('l)-.74 G .627(ine in UNIX messages \(that is, the line be)
+146.417 554.4 R .627(ginning `)-.15 F(`From<space>')-.74 E 3.127('i)-.74 G .627
+(nstead of `)424.797 554.4 R(`From:')-.74 E(';)-.74 E .502
+(the latter is the header from, which)102 566.4 R F2(does)3.002 E F1 .503
+(indicate the sender of the message\).)3.002 F .503(In pre)5.503 F .503
+(vious v)-.25 F(ersions,)-.15 E F2(sendmail)102 578.4 Q F1 .057(has tried to a)
+2.557 F -.2(vo)-.2 G .057(id changing the en).2 F -.15(ve)-.4 G .056
+(lope sender for back compatibility with UNIX con).15 F -.15(ve)-.4 G(n-).15 E
+.177(tion; at this point that back compatibility is creating too man)102 590.4
+R 2.678(yp)-.15 G .178(roblems, and it is necessary to mo)357.972 590.4 R -.15
+(ve)-.15 G(forw)102 602.4 Q(ard into the 1980s.)-.1 E F0 2.5(2.12. Command)87
+626.4 R(Line Flags)2.5 E F1(The)127 642.6 Q F0<ad42>2.5 E F1
+(\215ag has been added to pass in body type information.)2.5 E(The)127 658.8 Q
+F0<ad70>3.057 E F1 .557
+(\215ag has been added to pass in protocol information that w)3.057 F .557
+(as pre)-.1 F .556(viously passed in by)-.25 F(de\214ning the)102 670.8 Q F0
+($r)2.5 E F1(and)2.5 E F0($s)2.5 E F1(macros.)2.5 E(The)127 687 Q F0<ad58>2.6 E
+F1 .1(\215ag has been added to allo)2.6 F 2.6(wl)-.25 G .1
+(ogging of all protocol in and out of sendmail for deb)279.89 687 R(ug-)-.2 E
+2.732(ging. Y)102 699 R .232(ou can set \231\255X \214lename\232 and a complet\
+e transcript will be logged in that \214le.)-1.1 F .231(This gets big)5.231 F
+-.1(fa)102 711 S(st: the option is only for deb).1 E(ugging.)-.2 E EP
+%%Page: 6 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 294.65(6C)72 60 S(hanges in Sendmail V)378.87 60 Q
+(ersion 8)-1 E/F1 10/Times-Roman@0 SF(The)127 96 Q F0<ad71>4.006 E F1 1.507(\
+\215ag can limit limit a queue run to speci\214c recipients, senders, or queue\
+ ids using)4.006 F
+(\255qRsubstring, \255qSsubstring, or \255qIsubstring respecti)102 108 Q -.15
+(ve)-.25 G(ly).15 E(.)-.65 E F0 2.5(2.13. New)87 132 R(Con\214guration Line T)
+2.5 E(ypes)-.74 E F1 .674(The `T' \(T)127 148.2 R .674
+(rusted users\) con\214guration line has been deleted.)-.35 F .674
+(It will still be accepted b)5.674 F .674(ut will)-.2 F(be ignored.)102 160.2 Q
+(The `K' line has been added to declare database maps.)127 176.4 Q
+(The `V' line has been added to declare the con\214guration v)127 192.6 Q
+(ersion le)-.15 E -.15(ve)-.25 G(l.).15 E(The `M' \(mailer\) line tak)127 208.8
+Q(es a D= \214eld to specify e)-.1 E -.15(xe)-.15 G(cution directory).15 E(.)
+-.65 E F0 2.5(2.14. New)87 232.8 R(and Extended Options)2.5 E F1(Se)127 249 Q
+-.15(ve)-.25 G .9(ral ne).15 F 3.4(wo)-.25 G .9(ptions ha)184.8 249 R 1.2 -.15
+(ve b)-.2 H .9(een added, man).15 F 3.4(yt)-.15 G 3.4(os)314.89 249 S .9
+(upport ne)327.18 249 R 3.4(wf)-.25 G .9(eatures, others to allo)379.83 249 R
+3.4(wt)-.25 G(uning)481.22 249 Q(that w)102 261 Q(as pre)-.1 E(viously a)-.25 E
+-.25(va)-.2 G(ilable only by recompiling.).25 E(Brie\215y:)5 E 28.78(AT)102
+277.2 S .099(he alias \214le speci\214cation can no)144.11 277.2 R 2.599(wb)
+-.25 G 2.599(eal)286.654 277.2 S .099(ist of alias \214les.)303.512 277.2 R
+.098(Also, the con\214guration can spec-)5.099 F(ify a class of \214le.)138
+289.2 Q -.15(Fo)5 G 2.5(re).15 G(xample, to search the NIS aliases, use \231O)
+232.13 289.2 Q(Anis:mail.aliases\232.)-.35 E 31(bI)102 305.4 S
+(nsist on a minimum number of disk blocks.)141.33 305.4 Q 29.33(CD)102 321.6 S
+(eli)145.22 321.6 Q -.15(ve)-.25 G .24(ry checkpoint interv).15 F 2.74
+(al. Checkpoint)-.25 F .24(the queue \(to a)2.74 F -.2(vo)-.2 G .24
+(id duplicate deli).2 F -.15(ve)-.25 G .24(ries\) e).15 F -.15(ve)-.25 G .24
+(ry C).15 F(addresses.)138 333.6 Q 29.89(ED)102 349.8 S(ef)145.22 349.8 Q .712
+(ault error message.)-.1 F .711
+(This message \(or the contents of the indicated \214le\) are prepended)5.712 F
+(to error messages.)138 361.8 Q 28.78(GE)102 378 S .785(nable GECOS matching.)
+144.11 378 R .785(If you can')5.785 F 3.285<748c>-.18 G .786
+(nd a local user name and this option is enabled,)307.51 378 R .59
+(do a sequential scan of the passwd \214le to match ag)138 390 R .589
+(ainst full names.)-.05 F(Pre)5.589 E .589(viously a compile)-.25 F(option.)138
+402 Q 31(hM)102 418.2 S(aximum hop count.)146.89 418.2 Q(Pre)5 E
+(viously this w)-.25 E(as compiled in.)-.1 E 32.67(IT)102 434.4 S
+(his option has been e)144.11 434.4 Q(xtended to allo)-.15 E 2.5(ws)-.25 G
+(etting of resolv)300.64 434.4 Q(er parameters.)-.15 E 33.22(jS)102 450.6 S
+(end errors in MIME-encapsulated format.)143.56 450.6 Q 32.11(JF)102 466.8 S
+(orw)143.41 466.8 Q(ard \214le path.)-.1 E(Where to search for .forw)5 E
+(ard \214les \212 def)-.1 E(aults to $HOME/.forw)-.1 E(ard.)-.1 E 31(kC)102 483
+S .05(onnection cache size.)144.67 483 R .05
+(The total number of connections that will be k)5.05 F .05(ept open at an)-.1 F
+2.55(yt)-.15 G(ime.)486.5 483 Q 28.78(KC)102 499.2 S 1.395
+(onnection cache lifetime.)144.67 499.2 R 1.395(The amount of time an)6.395 F
+3.895(yc)-.15 G 1.394(onnection will be permitted to sit)364.53 499.2 R(idle.)
+138 511.2 Q 33.22(lE)102 527.4 S .333(nable Errors-T)144.11 527.4 R .333
+(o: header)-.8 F 5.334(.T)-.55 G .334
+(hese headers violate RFC 1123; this option is included to pro-)252.89 527.4 R
+(vide back compatibility with old v)138 539.4 Q(ersions of sendmail.)-.15 E
+28.78(OI)102 555.6 S(ncoming daemon options \(e.g., use alternate SMTP port\).)
+141.33 555.6 Q 31(pP)102 571.8 S(ri)143.56 571.8 Q -.25(va)-.25 G .3 -.15(cy o)
+.25 H 2.5(ptions. These).15 F(can be used to mak)2.5 E 2.5(ey)-.1 G
+(our SMTP serv)322.22 571.8 Q(er less friendly)-.15 E(.)-.65 E 32.67(rT)102 588
+S .67(his option has been e)144.11 588 R .67(xtended to allo)-.15 F 3.17<778c>
+-.25 G .67(ner grained control o)307 588 R -.15(ve)-.15 G 3.17(rt).15 G 3.17
+(imeouts. F)411.02 588 R .67(or e)-.15 F(xample,)-.15 E
+(you can set the timeout for SMTP commands indi)138 600 Q(vidually)-.25 E(.)
+-.65 E 29.33(RD)102 616.2 S(on')145.22 616.2 Q 11.797(tp)-.18 G 9.297
+(rune route-addrs.)177.947 616.2 R(Normally)269.851 616.2 Q 11.797(,i)-.65 G
+11.797(fv)324.608 616.2 S 9.297(ersion 8 sees an address lik)344.585 616.2 R(e)
+-.1 E 1.256("<@hostA,@hostB:user@hostC>, sendmail will try to strip of)138
+628.2 R 3.755(fa)-.25 G 3.755(sm)406.48 628.2 S 1.255(uch as it can \(up to)
+421.905 628.2 R(user@hostC\) as suggested by RFC 1123.)138 640.2 Q
+(This option disables that beha)5 E(viour)-.2 E(.)-.55 E 29.89(TT)102 656.4 S
+1.485(he \231Return T)144.11 656.4 R 3.985(oS)-.8 G 1.485
+(ender\232 timeout has been e)213.035 656.4 R 1.485(xtended to allo)-.15 F
+3.986(ws)-.25 G 1.486(peci\214cation of a w)399.942 656.4 R(arning)-.1 E .789
+(message interv)138 668.4 R .789
+(al, typically something on the order of four hours.)-.25 F .788
+(If a message cannot be)5.788 F(deli)138 680.4 Q -.15(ve)-.25 G 1.245
+(red in that interv).15 F 1.245(al, a w)-.25 F 1.245
+(arning message is sent back to the sender b)-.1 F 1.246(ut the message)-.2 F
+(continues to be tried.)138 692.4 Q 28.78(UU)102 708.6 S(ser database spec.)
+145.22 708.6 Q(This is still e)5 E(xperimental.)-.15 E EP
+%%Page: 7 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Changes in Sendmail V)72 60 Q(ersion 8)-1 E(7)499 60 Q
+/F1 10/Times-Roman@0 SF 28.78(VF)102 96 S .758(allback `)143.41 96 R(`MX')-.74
+E 3.258('h)-.74 G 3.258(ost. This)211.756 96 R .757
+(can be thought of as an MX host that applies to all addresses)3.258 F
+(that has a v)138 108 Q(ery high preference v)-.15 E
+(alue \(that is, use it only if e)-.25 E -.15(ve)-.25 G(rything else f).15 E
+(ails\).)-.1 E 28.78(wI)102 124.2 S 3.066(fs)141.33 124.2 S .566(et, assume th\
+at if you are the best MX host for a host, you should send directly to that)
+151.616 124.2 R 3.213(host. This)138 136.2 R .713
+(is intended for compatibility with UIUC sendmail, and may ha)3.213 F 1.013
+-.15(ve s)-.2 H .712(ome use on).15 F(\214re)138 148.2 Q -.1(wa)-.25 G(lls.).1
+E 31(7D)102 164.4 S 2.758(on)145.22 164.4 S .258(ot run eight bit clean.)
+157.978 164.4 R -.7(Te)5.258 G(chnically).7 E 2.758(,y)-.65 G .258(ou ha)
+305.656 164.4 R .558 -.15(ve t)-.2 H 2.758(oa).15 G .259
+(ssert this option to be RFC 821 com-)354.68 164.4 R(patible.)138 176.4 Q F0
+2.5(2.15. New)87 200.4 R(Mailer De\214nitions)2.5 E F1 21.75(L= Set)102 216.6 R
+.93(the allo)3.43 F -.1(wa)-.25 G .93(ble line length.).1 F .93
+(In V5, the L mailer \215ag implied a line length limit of 990)5.93 F
+(characters; this is no)138 228.6 Q 2.5(ws)-.25 G(ettable to an arbitrary v)
+233.29 228.6 Q(alue.)-.25 E 17.86(F=a T)102 244.8 R(ry to use ESMTP)-.35 E 5
+(.I)-1.11 G 2.5(tw)222.65 244.8 S(ill f)235.15 244.8 Q
+(all back to SMTP if the initial EHLO pack)-.1 E(et is rejected.)-.1 E 17.3
+(F=b Ensure)102 261 R 2.5(ab)2.5 G(lank line at the end of messages.)180.21 261
+Q(Useful on the *\214le* mailer)5 E(.)-.55 E 17.86(F=c Strip)102 277.2 R .68(a\
+ll comments from addresses; this should only be used as a last resort when dea\
+ling)3.18 F(with crank)138 289.2 Q 2.5(ym)-.15 G(ailers.)195.62 289.2 Q 17.3
+(F=g Ne)102 305.4 R -.15(ve)-.25 G 2.88(ru).15 G .38
+(se the null sender as the en)169.91 305.4 R -.15(ve)-.4 G .379(lope sender).15
+F 2.879(,e)-.4 G -.15(ve)343.645 305.4 S 2.879(nw).15 G .379(hen running SMTP)
+368.034 305.4 R 5.379(.T)-1.11 G .379(his violates)458.341 305.4 R(RFC 1123.)
+138 317.4 Q 17.3(F=7 Strip)102 333.6 R(all output to this mailer to 7 bits.)2.5
+E 16.19(F=L Used)102 349.8 R .198
+(to set the line limit to 990 bytes for SMTP compatibility)2.697 F 5.198(.I)
+-.65 G 2.698(tn)398.622 349.8 S .698 -.25(ow d)409.1 349.8 T .198
+(oes that only if the).25 F(L= k)138 361.8 Q -.15(ey)-.1 G
+(letter is not speci\214ed.).15 E
+(This \215ag is obsolete and should not be used.)5 E F0 2.5(2.16. New)87 385.8
+R(or Changed Pr)2.5 E(e-De\214ned Macr)-.18 E(os)-.18 E F1 23.5($k UUCP)102 402
+R(node name from uname\(2\).)2.5 E 20.72($m Domain)102 418.2 R
+(part of our full hostname.)2.5 E 23.5($_ RFC)102 434.4 R(1413-pro)2.5 E
+(vided sender address.)-.15 E 21.28($w Pre)102 450.6 R .148(viously w)-.25 F
+.148(as sometimes the full domain name, sometimes just the \214rst w)-.1 F
+2.647(ord. No)-.1 F 2.647(wg)-.25 G(uar)488.1 450.6 Q(-)-.2 E
+(anteed to be the \214rst w)138 462.6 Q
+(ord of the domain name \(i.e., the host name\).)-.1 E 25.72($j Pre)102 478.8 R
+.193(viously had to be de\214ned \212 it is no)-.25 F 2.693(wp)-.25 G .194
+(rede\214ned to be the full domain name, if that can)310.067 478.8 R
+(be determined.)138 490.8 Q(That is, it is equi)5 E -.25(va)-.25 G(lent to $w)
+.25 E(.$m.)-.65 E F0 2.5(2.17. New)87 514.8 R(and Changed Classes)2.5 E F1
+17.86($=k Initialized)102 531 R(to contain $k.)2.5 E 15.64($=w No)102 547.2 R
+3.069(wi)-.25 G .569
+(ncludes \231[1.2.3.4]\232 \(where 1.2.3.4 is your IP address\) to allo)163.039
+547.2 R 3.068(wt)-.25 G .568(he con\214guration \214le)422.314 547.2 R
+(to recognize your o)138 559.2 Q(wn IP address.)-.25 E F0 2.5(2.18. New)87
+583.2 R(Rewriting T)2.5 E(ok)-.92 E(ens)-.1 E F1(The)127 599.4 Q F0($&)3.25 E
+F1 .75(construct has been adopted from ID)3.25 F 3.25(At)-.4 G 3.25(od)322
+599.4 S .75(efer macro e)335.25 599.4 R -.25(va)-.25 G 3.25(luation. Normally)
+.25 F 3.25(,m)-.65 G(acros)482.9 599.4 Q .476
+(in rulesets are bound when the rule is \214rst parsed during startup.)102
+611.4 R .476(Some macros change during pro-)5.476 F .046
+(cessing and are uninteresting during startup.)102 623.4 R(Ho)5.046 E(we)-.25 E
+-.15(ve)-.25 G .846 -.4(r, t).15 H .047
+(hat macro can be referenced using \231$&x\232 to).4 F(defer the e)102 635.4 Q
+-.25(va)-.25 G(ulation of $x until the rule is processed.).25 E(The tok)127
+651.6 Q(ens)-.1 E F0($\()2.5 E F1(and)2.5 E F0($\))2.5 E F1(ha)2.5 E .3 -.15
+(ve b)-.2 H(een added to allo).15 E 2.5(ws)-.25 G(peci\214cation of map re)
+319.59 651.6 Q(writing.)-.25 E -1.11(Ve)127 667.8 S 1.499(rsion 8 allo)1.11 F
+(ws)-.25 E F0($@)3.999 E F1 1.499
+(on the Left Hand Side of an `R' line to match zero tok)3.999 F 3.998
+(ens. This)-.1 F(is)3.998 E(intended to be used to match the null input.)102
+679.8 Q EP
+%%Page: 8 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 294.65(8C)72 60 S(hanges in Sendmail V)378.87 60 Q
+(ersion 8)-1 E 2.5(2.19. Bigger)87 96 R(Defaults)2.5 E/F1 10/Times-Roman@0 SF
+-1.11(Ve)127 112.2 S 1.283(rsion 8 allo)1.11 F 1.284
+(ws up to 100 rulesets instead of 30.)-.25 F 1.284
+(It is recommended that rulesets 0\2559 be)6.284 F(reserv)102 124.2 Q
+(ed for sendmail')-.15 E 2.5(sd)-.55 G(edicated use in future releases.)202.66
+124.2 Q(The total number of MX records that can be used has been raised to 20.)
+127 140.4 Q .335(The number of queued messages that can be handled at one time\
+ has been raised from 600 to)127 156.6 R(1000.)102 168.6 Q F0 2.5(2.20. Differ)
+87 192.6 R(ent Default T)-.18 E(uning P)-.92 E(arameters)-.1 E F1 -1.11(Ve)127
+208.8 S .8(rsion 8 has changed the def)1.11 F .8
+(ault parameters for tuning queue costs to mak)-.1 F 3.3(et)-.1 G .8
+(he number of)449.08 208.8 R .712(recipients more important than the size of t\
+he message \(for small messages\).)102 220.8 R .712(This is reasonable if)5.712
+F(you are connected with reasonably f)102 232.8 Q(ast links.)-.1 E F0 2.5
+(2.21. A)87 256.8 R(uto-Quoting in Addr)-.5 E(esses)-.18 E F1(Pre)127 273 Q
+(viously)-.25 E 3.2(,t)-.65 G .701(he `)177.36 273 R .701
+(`Full Name <email address>')-.74 F 3.201('s)-.74 G .701(yntax w)322.025 273 R
+.701(ould generate incorrect protocol out-)-.1 F .006(put if `)102 285 R .006
+(`Full Name')-.74 F 2.506('h)-.74 G .006(ad special characters such as dot.)
+187.754 285 R .005(This v)5.006 F .005(ersion puts quotes around such names.)
+-.15 F F0 2.5(2.22. Symbolic)87 309 R(Names On Err)2.5 E(or Mailer)-.18 E F1
+(Se)127 325.2 Q -.15(ve)-.25 G(ral names ha).15 E .3 -.15(ve b)-.2 H(een b).15
+E(uilt in to the $@ portion of the $#error mailer)-.2 E 5(.F)-.55 G(or e)428.96
+325.2 Q(xample:)-.15 E($#error $@NOHOST $: Host unkno)142 341.4 Q(wn)-.25 E
+(Prints the indicated message and sets the e)102 357.6 Q(xit status of)-.15 E
+/F2 10/Times-Italic@0 SF(sendmail)2.5 E F1(to)2.5 E/F3 9/Times-Roman@0 SF
+(EX_NOHOST)2.5 E F1(.)A F0 2.5(2.23. New)87 381.6 R(Built-In Mailers)2.5 E F1
+-1 -.8(Tw o)127 397.8 T(ne)3.901 E 3.101(wm)-.25 G .601(ailers, *\214le* and *\
+include*, are included to de\214ne options when mailing to a \214le)174.822
+397.8 R(or a :include: \214le respecti)102 409.8 Q -.15(ve)-.25 G(ly).15 E 5
+(.P)-.65 G(re)232.88 409.8 Q(viously these were o)-.25 E -.15(ve)-.15 G
+(rloaded on the local mailer).15 E(.)-.55 E F0 2.5(2.24. SMTP)87 433.8 R
+(VRFY Doesn't Expand)2.5 E F1(Pre)127 450 Q 1.438(vious v)-.25 F 1.438
+(ersions of sendmail treated VRFY and EXPN the same.)-.15 F 1.437(In this v)
+6.437 F 1.437(ersion, VRFY)-.15 F(doesn')102 462 Q 2.5(te)-.18 G
+(xpand aliases or follo)138.05 462 Q 2.5(w.)-.25 G(forw)235.84 462 Q
+(ard \214les.)-.1 E .663(As an optimization, if you run with your def)127 478.2
+R .664(ault deli)-.1 F -.15(ve)-.25 G .664(ry mode being queue-only).15 F 3.164
+(,t)-.65 G .664(he RCPT)466.386 478.2 R 1.09
+(command will also not chase aliases and .forw)102 490.2 R 1.09(ard \214les.)
+-.1 F 1.09(It will chase them when it processes the)6.09 F 2.5(queue. This)102
+502.2 R(speeds up RCPT processing.)2.5 E F0 2.5(2.25. [IPC])87 526.2 R
+(Mailers Allo)2.5 E 2.5(wM)-.1 G(ultiple Hosts)210.49 526.2 Q F1 .099
+(When an address resolv)127 542.4 R .099(es to a mailer that has `)-.15 F
+(`[IPC]')-.74 E 2.599('a)-.74 G 2.6(si)353.52 542.4 S .1(ts `)362.79 542.4 R
+(`P)-.74 E(ath')-.15 E .1(', the $@ part \(host name\))-.74 F .138
+(can be a colon-separated list of hosts instead of a single hostname.)102 554.4
+R .137(This asks sendmail to search the)5.137 F .16
+(list for the \214rst entry that is a)102 566.4 R -.25(va)-.2 G .16(ilable e)
+.25 F .161(xactly as though it were an MX record.)-.15 F .161
+(The intent is to route)5.161 F .738(internal traf)102 578.4 R .738
+(\214c through internal netw)-.25 F .738
+(orks without publishing an MX record to the net.)-.1 F .737(MX e)5.737 F
+(xpan-)-.15 E(sion is still done on the indi)102 590.4 Q(vidual items.)-.25 E
+F0 2.5(2.26. Aliases)87 614.4 R(Extended)2.5 E F1 .298
+(The implementation has been mer)127 630.6 R .298(ged with maps.)-.18 F .299
+(Among other things, this supports multiple)5.298 F
+(alias \214les and NIS-based aliases.)102 642.6 Q -.15(Fo)5 G 2.5(re).15 G
+(xample:)258.34 642.6 Q -.35(OA)142 658.8 S(/etc/aliases,nis:mail.aliases).35 E
+(will search \214rst the local database \231/etc/aliases\232 follo)102 675 Q
+(wed by the NIS map)-.25 E EP
+%%Page: 9 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Changes in Sendmail V)72 60 Q(ersion 8)-1 E(9)499 60 Q
+2.5(2.27. P)87 96 R(ortability and Security Enhancements)-.2 E/F1 10
+/Times-Roman@0 SF 2.5(An)127 112.2 S(umber of internal changes ha)141.72 112.2
+Q .3 -.15(ve b)-.2 H(een made to enhance portability).15 E(.)-.65 E(Se)127
+128.4 Q -.15(ve)-.25 G(ral \214x).15 E(es ha)-.15 E .3 -.15(ve b)-.2 H
+(een made to increase the paranoia f).15 E(actor)-.1 E(.)-.55 E .46
+(In particular)127 144.6 R 2.96(,t)-.4 G .46(he permissions required for .forw)
+184.45 144.6 R .46(ard and :include: \214les ha)-.1 F .76 -.15(ve b)-.2 H .46
+(een tightened up).15 F(considerably)102 156.6 Q 5.182(.V)-.65 G 2.683(5w)
+167.352 156.6 S .183(ould pretty much read an)182.155 156.6 R 2.683<798c>-.15 G
+.183(le it could get to as root, which e)295.96 156.6 R .183(xposed some secu-)
+-.15 F 1.02(rity holes.)102 168.6 R 1.02
+(V8 insists that all directories leading up to the .forw)6.02 F 1.02
+(ard or :include: \214le be searchable)-.1 F .334
+(\("x" permission\) by the controlling user" \(de\214ned belo)102 180.6 R .335
+(w\), that the \214le itself be readable by the con-)-.25 F(trolling user)102
+192.6 Q 2.5(,a)-.4 G(nd that .forw)159.65 192.6 Q(ard \214les be o)-.1 E
+(wned by the user who is being forw)-.25 E(arded to or root.)-.1 E .565
+(The "controlling user" is the user on whose behalf the mail is being deli)127
+208.8 R -.15(ve)-.25 G 3.065(red. F).15 F .565(or e)-.15 F(xample,)-.15 E .459
+(if you mail to "user1" then the controlling user for ~user1/.forw)102 220.8 R
+.46(ard and an)-.1 F 2.96(ym)-.15 G .46(ailers in)416.94 220.8 R -.2(vo)-.4 G
+-.1(ke).2 G 2.96(db).1 G 2.96(yt)481.04 220.8 S(hat)491.78 220.8 Q(.forw)102
+232.8 Q(ard \214le, including :include: \214les.)-.1 E(Pre)127 249 Q(viously)
+-.25 E 2.816(,a)-.65 G -.15(ny)178.636 249 S .316
+(one who had a home directory could create a .forw).15 F .316(ard could forw)
+-.1 F .316(ard to a pro-)-.1 F 2.965(gram. No)102 261 R 1.765 -.65(w, s)-.25 H
+.466(endmail checks to mak).65 F 2.966(es)-.1 G .466(ure that the)262.934 261 R
+2.966(yh)-.15 G -2.25 -.2(av e)321.672 261 T .466(an "appro)3.166 F -.15(ve)
+-.15 G 2.966(ds).15 G .466(hell", that is, a shell listed)398.42 261 R
+(in the /etc/shells \214le.)102 273 Q F0 2.5(2.28. Miscellaneous)87 297 R
+(Fixes and Enhancements)2.5 E F1 4.03(An)127 313.2 S 1.53(umber of small b)
+143.25 313.2 R 1.53(ugs ha)-.2 F 1.53(ving to do with things lik)-.2 F 4.03(eb)
+-.1 G 1.53(ackslash-escaped quotes inside of)364.72 313.2 R(comments ha)102
+325.2 Q .3 -.15(ve b)-.2 H(een \214x).15 E(ed.)-.15 E 1.552(The \214x)127 341.4
+R 1.552(ed size limit on header lines \(such as \231T)-.15 F 1.553
+(o:\232 and \231Cc:\232\) has been eliminated; those)-.8 F -.2(bu)102 353.4 S
+-.25(ff).2 G(ers are dynamically allocated no).25 E -.65(w.)-.25 G .289(Sendma\
+il writes a /etc/sendmail.pid \214le with the current process id and the curre\
+nt in)127 369.6 R -.2(vo)-.4 G(cation).2 E(\215ags.)102 381.6 Q -1 -.8(Tw o)127
+397.8 T .218
+(people using the same program \(e.g., submit\) are considered "dif)3.518 F
+.219(ferent" so that duplicate)-.25 F .508(elimination doesn')102 409.8 R 3.008
+(td)-.18 G .508(elete one of them.)187.836 409.8 R -.15(Fo)5.508 G 3.008(re).15
+G .508(xample, tw)287.556 409.8 R 3.008(op)-.1 G .508(eople forw)345.412 409.8
+R .508(arding their email to |submit)-.1 F(will be treated as tw)102 421.8 Q
+2.5(or)-.1 G(ecipients.)193.27 421.8 Q .721(The mailstats program prints maile\
+r names and gets the location of the sendmail.st \214le from)127 438 R
+(/etc/sendmail.cf.)102 450 Q(Man)127 466.2 Q 2.5(ym)-.15 G(inor b)160.46 466.2
+Q(ugs ha)-.2 E .3 -.15(ve b)-.2 H(een \214x).15 E
+(ed, such as handling of backslashes inside of quotes.)-.15 E 2.5(Ah)127 482.4
+S(ook has been added to allo)141.72 482.4 Q 2.5(wr)-.25 G -.25(ew)260.89 482.4
+S(riting of local addresses after aliasing.).25 E F0 2.5(3. FUTURE)72 506.4 R
+-.1(WO)2.5 G(RK).1 E F1 1.719(The pre)112 522.6 R 1.719
+(vious section describes)-.25 F/F2 10/Times-Italic@0 SF(sendmail)4.219 E F1
+1.719(as of v)4.219 F 1.719(ersion 8.6.6.)-.15 F 1.718
+(There is still much to be done.)6.719 F(Some high points are described belo)87
+534.6 Q 3.8 -.65(w. T)-.25 H(his list is by no means e).65 E(xhausti)-.15 E
+-.15(ve)-.25 G(.).15 E F0 2.5(3.1. Full)87 558.6 R(MIME Support)2.5 E F1
+(Currently)127 574.8 Q F2(sendmail)3.305 E F1 .805(only supports se)3.305 F
+-.15(ve)-.25 G 3.305(nb).15 G .805(it MIME messages.)297.005 574.8 R .806
+(Although it can pass eight bit)5.805 F .371(MIME messages, it cannot adv)102
+586.8 R .371(ertise that f)-.15 F .37
+(act because the standards say that the mail agent must be)-.1 F .26
+(able to do 8- to 7-bit con)102 598.8 R -.15(ve)-.4 G .26(rsion to ha).15 F
+.561 -.15(ve f)-.2 H .261(ull 8-bit support.).15 F .261(This requires f)5.261 F
+.261(ar more e)-.1 F(xtensi)-.15 E .561 -.15(ve m)-.25 H(odi\214-).15 E
+(cation of the message body than is currently supported.)102 610.8 Q .464
+(The best w)127 627 R .464(ay to do this w)-.1 F .463
+(ould be to support the general concept of an e)-.1 F .463(xternal `)-.15 F
+.463(`message \214l-)-.74 F(ter')102 639 Q 3.319('t)-.74 G .819
+(hat could do arbitrary modi\214cations of the message.)124.569 639 R .819
+(This w)5.819 F .82(ould allo)-.1 F 3.32(wM)-.25 G .82(IME con)427.37 639 R
+-.15(ve)-.4 G .82(rsion as).15 F .63
+(well as such things as automatic encryption of messages sent o)102 651 R -.15
+(ve)-.15 G 3.129(re).15 G .629(xternal links.)379.264 651 R .629
+(This is probably)5.629 F(an e)102 663 Q(xtremely non-tri)-.15 E(vial change.)
+-.25 E F0 2.5(3.2. Ser)87 687 R(vice Switch Abstraction)-.1 E F1 .369(Most mod\
+ern systems include some concept of a \231service switch\232 \212 for e)127
+703.2 R .37(xample, to look up)-.15 F .984
+(host names you can try DNS, NIS, NIS+, te)102 715.2 R .984
+(xt tables, NetInfo, or other services in some arbitrary)-.15 F EP
+%%Page: 10 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 287.15(10 Changes)72 60 R(in Sendmail V)2.5 E(ersion 8)
+-1 E/F1 10/Times-Roman@0 SF(order)102 96 Q 5.174(.T)-.55 G .174
+(his is currently v)136.334 96 R .174(ery clumsy in)-.15 F/F2 10/Times-Italic@0
+SF(sendmail)2.674 E F1 2.674(,w)C .174
+(ith only limited control of the services pro)309.612 96 R(vided.)-.15 E F0 2.5
+(3.3. Mor)87 120 R 2.5(eC)-.18 G(ontr)139.86 120 Q(ol of Local Addr)-.18 E
+(esses)-.18 E F1 .943(Currently some addresses are declared as \231local\232 a\
+nd are handled specially \212 for e)127 136.2 R(xample,)-.15 E(the)102 148.2 Q
+3.455(ym)-.15 G .955(ay ha)130.305 148.2 R 1.255 -.15(ve .)-.2 H(forw).15 E
+.956(ard \214les, may be translated into program calls or \214le deli)-.1 F
+-.15(ve)-.25 G .956(ries, and so forth.).15 F .311(These should be brok)102
+160.2 R .311(en out into separate \215ags to allo)-.1 F 2.811(wt)-.25 G .31
+(he local system administrator to ha)330.29 160.2 R .61 -.15(ve m)-.2 H(ore).15
+E(\214ne-grained control o)102 172.2 Q -.15(ve)-.15 G 2.5(ro).15 G(perations.)
+208.62 172.2 Q F0 2.5(3.4. Mor)87 196.2 R 2.5(eR)-.18 G(un-T)139.86 196.2 Q
+(ime Con\214guration Options)-.18 E F1 .016(There are man)127 212.4 R 2.516(yo)
+-.15 G .016(ptions that are con\214gured at compile time, such as the method o\
+f \214le locking)197.148 212.4 R .719
+(and the use of the IDENT protocol [RFC1413].)102 224.4 R .719
+(These should be transfered to run time by adding)5.719 F(ne)102 236.4 Q 2.5
+(wo)-.25 G(ptions.)125.91 236.4 Q(Similarly)127 252.6 Q 3.413(,s)-.65 G .913
+(ome options are currently o)173.383 252.6 R -.15(ve)-.15 G .913
+(rloaded, that is, a single option controls more than).15 F(one thing.)102
+264.6 Q(These should probably be brok)5 E(en out into separate options.)-.1 E
+(This implies that options will change from single characters to w)127 280.8 Q
+(ords.)-.1 E F0 2.5(3.5. Mor)87 304.8 R 2.5(eC)-.18 G(on\214guration Contr)
+139.86 304.8 Q(ol Ov)-.18 E(er Err)-.1 E(ors)-.18 E F1(Currently)127 321 Q
+3.649(,t)-.65 G 1.148
+(he con\214guration \214le can generate an error message during parsing.)
+173.609 321 R(Ho)6.148 E(we)-.25 E -.15(ve)-.25 G 1.948 -.4(r, i).15 H(t).4 E
+.569(cannot tweak other operations, such as issuing a w)102 333 R .57
+(arning message to the system postmaster)-.1 F 5.57(.S)-.55 G(imi-)487.33 333 Q
+(larly)102 345 Q 2.558(,s)-.65 G .057
+(ome errors should not be triggered if the)128.628 345 R 2.557(ya)-.15 G .057
+(re in aliases during an alias \214le reb)302.237 345 R .057(uild, b)-.2 F .057
+(ut should)-.2 F(be triggered if that alias is actually used.)102 357 Q F0 2.5
+(3.6. Long)87 381 R -.92(Te)2.5 G(rm Host State).92 E F1(Currently)127 397.2 Q
+(,)-.65 E F2(sendmail)3.731 E F1 1.231
+(only remembers host status during a single queue run.)3.731 F 1.232
+(This should be)6.232 F(con)102 409.2 Q -.15(ve)-.4 G .492(rted to long term s\
+tatus stored on disk so it can be shared between instantiations of).15 F F2
+(sendmail)2.991 E F1(.)A .866(Entries will ha)102 421.2 R 1.167 -.15(ve t)-.2 H
+3.367(ob).15 G 3.367(et)190.666 421.2 S .867(imestamped so the)201.253 421.2 R
+3.367(yc)-.15 G .867(an time out.)290.084 421.2 R .867(This will allo)5.867 F
+(w)-.25 E F2(sendmail)3.367 E F1 .867(to implement)3.367 F -.15(ex)102 433.2 S
+(ponential back).15 E(of)-.1 E 2.5(fo)-.25 G 2.5(nq)188.7 433.2 S
+(ueue runs on a per)201.2 433.2 Q(-host basis.)-.2 E F0 2.5(3.7. Connection)87
+457.2 R(Contr)2.5 E(ol)-.18 E F1 .819(Modern netw)127 473.4 R .819(orks ha)-.1
+F 1.119 -.15(ve d)-.2 H(if).15 E .819(ferent types of connecti)-.25 F .818
+(vity than the past.)-.25 F .818(In particular)5.818 F 3.318(,t)-.4 G .818
+(he rising)468.462 473.4 R .636
+(prominence of dialup IP has created certain challenges for automated serv)102
+485.4 R 3.136(ers. It)-.15 F .636(is not uncommon)3.136 F .732(to try to mak)
+102 497.4 R 3.232(eac)-.1 G .732(onnection to a host and ha)175.27 497.4 R
+1.032 -.15(ve i)-.2 H 3.232(tf).15 G .732(ail, e)307.984 497.4 R -.15(ve)-.25 G
+3.232(nt).15 G .732(hough if you tried ag)348.208 497.4 R .732(ain it w)-.05 F
+.731(ould suc-)-.1 F 2.5(ceed. The)102 509.4 R
+(connection management could be a bit cle)2.5 E -.15(ve)-.25 G
+(rer to try to adapt to such situations.).15 E F0 2.5(3.8. Other)87 533.4 R
+(Caching)2.5 E F1 .074(When you do an MX record lookup, the name serv)127 549.6
+R .075(er automatically returns the IP addresses of)-.15 F .518
+(the associated MX serv)102 561.6 R 3.018(ers. This)-.15 F .518
+(information is currently ignored, and another query is done to get)3.018 F
+(this information.)102 573.6 Q(It should be cached to a)5 E -.2(vo)-.2 G(id e)
+.2 E(xcess name serv)-.15 E(er traf)-.15 E(\214c.)-.25 E F0 2.5(4. REFERENCES)
+72 597.6 R F1([Allman83a])87 613.8 Q .137(\231Sendmail \212 An Internetw)123
+625.8 R .137(ork Mail Router)-.1 F 4.037 -.7(.\232 E)-.55 H 2.638(.A).7 G 2.638
+(llman. In)327.58 625.8 R F2 .138(Unix Pr)2.638 F -.1(og)-.45 G -.15(ra).1 G
+(mmer).15 E(s')-.1 E 2.638(sM)-.4 G(anual,)463.582 625.8 Q F1(4.2)2.638 E(Berk)
+123 637.8 Q(ele)-.1 E 2.5(yS)-.15 G(oftw)166.91 637.8 Q(are Distrib)-.1 E
+(ution, v)-.2 E(olume 2C.)-.2 E(August 1983.)5 E([Allman83b])87 654 Q .384
+(\231Mail Systems and Addressing in 4.2BSD.)123 666 R 5.384<9a45>-.7 G 2.884
+(.A)311.544 666 S .383(llman In)324.148 666 R F2 .383(UNICOM Confer)2.883 F
+.383(ence Pr)-.37 F(oceedings.)-.45 E F1(San Die)123 678 Q(go, California.)-.15
+E(January 1983.)5 E([Allman&Amos85])87 694.2 Q -.74(``)123 706.2 S 1.145
+(Sendmail Re).74 F(visited.)-.25 E 5.125 -.74('' E)-.7 H 3.645(.A).74 G 1.145
+(llman and M. Amos.)241.215 706.2 R(In)6.145 E F2 1.145
+(Usenix Summer 1985 Confer)3.645 F 1.145(ence Pr)-.37 F(o-)-.45 E(ceedings.)123
+718.2 Q F1(Portland, Ore)5 E 2.5(gon. June)-.15 F(1985.)2.5 E EP
+%%Page: 11 11
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Changes in Sendmail V)72 60 Q(ersion 8)-1 E(11)494 60 Q
+/F1 10/Times-Roman@0 SF([ID)87 96 Q(A87])-.4 E/F2 10/Times-Italic@0 SF(Electr)
+1.97 E .983(onic Mail Addr)-.45 F .983(essing in Theory and Pr)-.37 F .982
+(actice with the ID)-.15 F 3.482(AS)-.35 G .982(endmail Enhancement Kit)398.156
+96 R .563(\(or The P)123 108 R(ostmaster')-.8 E 3.063(sL)-.4 G .563(ast W)
+215.989 108 R .564(ill and T)-.55 F(estament\).)-.92 E F1 .564(Lennart Lo)5.564
+F -.5(..)359.828 102 S 3.064(vstrand. Department)364.828 108 R .564
+(of Computer)3.064 F 1.267(and Information Science, Uni)123 120 R -.15(ve)-.25
+G 1.267(rsity of Link).15 F(o)-.1 E -.5(..)306.585 114 S 1.266
+(ping, Sweden, Report no. LiTH-ID)311.585 120 R(A-Ex-8715.)-.4 E(May 1987.)123
+132 Q([RFC821])87 148.2 Q F2(Simple Mail T)123 160.2 Q -.15(ra)-.55 G
+(nsport Pr).15 E(otocol.)-.45 E F1(J. Postel.)5 E(August 1982.)5 E([RFC1123])87
+176.4 Q F2(Requir)123 188.4 Q .163
+(ements for Internet Hosts \212 Application and Support.)-.37 F F1 .164
+(Internet Engineering T)5.164 F .164(ask F)-.8 F(orce,)-.15 E
+(R. Braden, Editor)123 200.4 Q 5(.O)-.55 G(ctober 1989.)207.72 200.4 Q
+([RFC1344])87 216.6 Q F2(Implications of MIME for Internet Mail Gate)123 228.6
+Q(ways.)-.15 E F1(N. Borenstein.)5 E(June 1992.)5 E([RFC1413])87 244.8 Q F2
+(Identi\214cation Pr)123 256.8 Q(otocol.)-.45 E F1(M. St. Johns.)5 E
+(February 1993.)5 E([RFC1425])87 273 Q F2 2.352(SMTP Service Extensions.)123
+285 R F1 2.352(J. Klensin, N. Freed, M. Rose, E. Stef)7.352 F 2.351
+(ferud, and D. Crock)-.25 F(er)-.1 E(.)-.55 E(February 1993.)123 297 Q
+([RFC1426])87 313.2 Q F2 .12(SMTP Service Extension for 8bit-MIMEtr)123 325.2 R
+(ansport.)-.15 E F1 .12(J. Klensin, N. Freed, M. Rose, E. Stef)5.12 F(ferud,)
+-.25 E(and D. Crock)123 337.2 Q(er)-.1 E 5(.F)-.55 G(ebruary 1993.)196.78 337.2
+Q([RFC1427])87 353.4 Q F2 .813(SMTP Service Extension for Messa)123 365.4 R
+1.013 -.1(ge S)-.1 H .813(ize Declar).1 F(ation.)-.15 E F1 .813
+(J. Klensin, N. Freed, and K. Moore.)5.813 F(February 1993.)123 377.4 Q
+([RFC1521])87 393.6 Q F2 2.033
+(MIME \(Multipurpose Internet Mail Extensions\) P)123 405.6 R 2.033
+(art One: Mec)-.8 F 2.033(hanisms for Specifying and)-.15 F .933
+(Describing the F)123 417.6 R .933(ormat of Internet Messa)-1.05 F 1.133 -.1
+(ge B)-.1 H(odies.).1 E F1 .932(N. Borenstein and N. Freed.)5.932 F(September)
+5.932 E(1993.)123 429.6 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/usr.sbin/sendmail/doc/intro/Makefile b/usr.sbin/sendmail/doc/intro/Makefile
new file mode 100644
index 0000000..939cd6c
--- /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 0000000..0406bb1
--- /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/intro/intro.ps b/usr.sbin/sendmail/doc/intro/intro.ps
new file mode 100644
index 0000000..57c4216
--- /dev/null
+++ b/usr.sbin/sendmail/doc/intro/intro.ps
@@ -0,0 +1,1295 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Italic
+%%+ font Times-Bold
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 13
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Italic
+%%IncludeResource: font Times-Bold
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 14/Times-Roman@0 SF(SENDMAIL \212 An Internetw)159.172 141 Q
+(ork Mail Router)-.14 E/F1 10/Times-Roman@0 SF(Eric Allman*)260.92 165 Q/F2 10
+/Times-Italic@0 SF(Univer)220.2 183 Q(sity of California, Berk)-.1 E(ele)-.1 E
+(y)-.3 E(Mammoth Pr)251.98 195 Q(oject)-.45 E F1(ABSTRA)262.085 227.4 Q(CT)-.4
+E 1.41(Routing mail through a heterogenous internet presents man)112 243.6 R
+3.91(yn)-.15 G 1.91 -.25(ew p)372.55 243.6 T 3.91(roblems. Among).25 F .297
+(the w)112 255.6 R .297(orst of these is that of address mapping.)-.1 F
+(Historically)5.297 E 2.797(,t)-.65 G .298(his has been handled on an)355.03
+255.6 R F2(ad hoc)112 267.6 Q F1 2.5(basis. Ho)2.5 F(we)-.25 E -.15(ve)-.25 G
+.8 -.4(r, t).15 H(his approach has become unmanageable as internets gro).4 E
+-.65(w.)-.25 G .15(Sendmail acts a uni\214ed "post of)112 283.8 R .15
+(\214ce" to which all mail can be submitted.)-.25 F .15(Address inter)5.15 F(-)
+-.2 E .426(pretation is controlled by a production system, which can parse bot\
+h domain-based ad-)112 295.8 R .423(dressing and old-style)112 307.8 R F2 .423
+(ad hoc)2.923 F F1 2.923(addresses. The)2.923 F .422(production system is po)
+2.922 F .422(werful enough to)-.25 F(re)112 319.8 Q 1.357(write addresses in t\
+he message header to conform to the standards of a number of)-.25 F 1.15
+(common tar)112 331.8 R 1.15(get netw)-.18 F 1.15
+(orks, including old \(NCP/RFC733\) Arpanet, ne)-.1 F 3.65(w\()-.25 G
+(TCP/RFC822\))405.65 331.8 Q 1.119(Arpanet, UUCP)112 343.8 R 3.619(,a)-1.11 G
+1.119(nd Phonenet.)186.448 343.8 R 1.119(Sendmail also implements an SMTP serv)
+6.119 F(er)-.15 E 3.619(,m)-.4 G(essage)437.9 343.8 Q(queueing, and aliasing.)
+112 355.8 Q F2(Sendmail)97 400.2 Q F1 .501(implements a general internetw)3 F
+.501(ork mail routing f)-.1 F(acility)-.1 E 3.001(,f)-.65 G .501
+(eaturing aliasing and forw)369.847 400.2 R(arding,)-.1 E
+(automatic routing to netw)72 412.2 Q(ork g)-.1 E(ate)-.05 E -.1(wa)-.25 G
+(ys, and \215e).1 E(xible con\214guration.)-.15 E .624(In a simple netw)97
+428.4 R .624(ork, each node has an address, and resources can be identi\214ed \
+with a host-resource)-.1 F .374(pair; in particular)72 440.4 R 2.874(,t)-.4 G
+.374(he mail system can refer to users using a host-username pair)149.932 440.4
+R 5.374(.H)-.55 G .375(ost names and numbers)409.276 440.4 R(ha)72 452.4 Q .3
+-.15(ve t)-.2 H 2.5(ob).15 G 2.5(ea)108.31 452.4 S
+(dministered by a central authority)119.69 452.4 Q 2.5(,b)-.65 G
+(ut usernames can be assigned locally to each host.)263.82 452.4 Q .649
+(In an internet, multiple netw)97 468.6 R .649(orks with dif)-.1 F .649
+(ferent characterstics and managements must communicate.)-.25 F .389
+(In particular)72 480.6 R 2.889(,t)-.4 G .389
+(he syntax and semantics of resource identi\214cation change.)129.308 480.6 R
+.39(Certain special cases can be han-)5.389 F 1.033(dled tri)72 492.6 R 1.033
+(vially by)-.25 F F2 1.033(ad hoc)3.533 F F1 1.032(techniques, such as pro)
+3.533 F 1.032(viding netw)-.15 F 1.032
+(ork names that appear local to hosts on other)-.1 F(netw)72 504.6 Q 1.454
+(orks, as with the Ethernet at Xerox P)-.1 F 3.955(ARC. Ho)-.92 F(we)-.25 E
+-.15(ve)-.25 G 4.755 -.4(r, t).15 H 1.455(he general case is e).4 F 1.455
+(xtremely comple)-.15 F 3.955(x. F)-.15 F(or)-.15 E -.15(ex)72 516.6 S .192
+(ample, some netw).15 F .192(orks require point-to-point routing, which simpli\
+\214es the database update problem since)-.1 F .618(only adjacent hosts must b\
+e entered into the system tables, while others use end-to-end addressing.)72
+528.6 R(Some)5.618 E(netw)72 540.6 Q .123(orks use a left-associati)-.1 F .423
+-.15(ve s)-.25 H .123(yntax and others use a right-associati).15 F .423 -.15
+(ve s)-.25 H .123(yntax, causing ambiguity in mix).15 F(ed)-.15 E(addresses.)72
+552.6 Q .678(Internet standards seek to eliminate these problems.)97 568.8 R
+(Initially)5.678 E 3.178(,t)-.65 G .679(hese proposed e)353.134 568.8 R .679
+(xpanding the address)-.15 F .65(pairs to address triples, consisting of {netw)
+72 580.8 R .649(ork, host, resource} triples.)-.1 F(Netw)5.649 E .649
+(ork numbers must be uni)-.1 F -.15(ve)-.25 G -.2(r-).15 G 1.452
+(sally agreed upon, and hosts can be assigned locally on each netw)72 592.8 R
+3.952(ork. The)-.1 F(user)3.952 E(-le)-.2 E -.15(ve)-.25 G 3.952(lp).15 G 1.452
+(resentation w)440.718 592.8 R(as)-.1 E 2.352(quickly e)72 604.8 R 2.352(xpand\
+ed to address domains, comprised of a local resource identi\214cation and a hi\
+erarchical)-.15 F .256(domain speci\214cation with a common static root.)72
+616.8 R .257(The domain technique separates the issue of ph)5.257 F .257
+(ysical v)-.05 F(er)-.15 E(-)-.2 E .807(sus logical addressing.)72 628.8 R -.15
+(Fo)5.807 G 3.307(re).15 G .807
+(xample, an address of the form \231eric@a.cc.berk)191.028 628.8 R(ele)-.1 E
+-.65(y.)-.15 G .807(arpa\232 describes only the).65 F(logical or)72 640.8 Q
+-.05(ga)-.18 G(nization of the address space.).05 E F2(Sendmail)97 657 Q F1
+.493(is intended to help bridge the g)2.992 F .493(ap between the totally)-.05
+F F2 .493(ad hoc)2.993 F F1 -.1(wo)2.993 G .493(rld of netw).1 F .493
+(orks that kno)-.1 F(w)-.25 E .855
+(nothing of each other and the clean, tightly-coupled w)72 669 R .854
+(orld of unique netw)-.1 F .854(ork numbers.)-.1 F .854(It can accept old)5.854
+F .32 LW 76 678.6 72 678.6 DL 80 678.6 76 678.6 DL 84 678.6 80 678.6 DL 88
+678.6 84 678.6 DL 92 678.6 88 678.6 DL 96 678.6 92 678.6 DL 100 678.6 96 678.6
+DL 104 678.6 100 678.6 DL 108 678.6 104 678.6 DL 112 678.6 108 678.6 DL 116
+678.6 112 678.6 DL 120 678.6 116 678.6 DL 124 678.6 120 678.6 DL 128 678.6 124
+678.6 DL 132 678.6 128 678.6 DL 136 678.6 132 678.6 DL 140 678.6 136 678.6 DL
+144 678.6 140 678.6 DL 148 678.6 144 678.6 DL 152 678.6 148 678.6 DL 156 678.6
+152 678.6 DL 160 678.6 156 678.6 DL 164 678.6 160 678.6 DL 168 678.6 164 678.6
+DL 172 678.6 168 678.6 DL 176 678.6 172 678.6 DL 180 678.6 176 678.6 DL 184
+678.6 180 678.6 DL 188 678.6 184 678.6 DL 192 678.6 188 678.6 DL 196 678.6 192
+678.6 DL 200 678.6 196 678.6 DL 204 678.6 200 678.6 DL 208 678.6 204 678.6 DL
+212 678.6 208 678.6 DL 216 678.6 212 678.6 DL/F3 8/Times-Roman@0 SF .557
+(*A considerable part of this w)93.6 690.6 R .557(ork w)-.08 F .557
+(as done while under the emplo)-.08 F 2.557(yo)-.08 G 2.556(ft)323.116 690.6 S
+.556(he INGRES Project at the Uni)330.56 690.6 R -.12(ve)-.2 G .556
+(rsity of California at).12 F(Berk)72 700.2 Q(ele)-.08 E 2(ya)-.12 G
+(nd at Britton Lee.)106.232 700.2 Q/F4 10/Times-Bold@0 SF
+(SENDMAIL \212 An Inter)72 756 Q(netw)-.15 E(ork Mail Router)-.1 E(SMM:9-1)
+462.9 756 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 192.28(SMM:9-2 SENDMAIL)72 60 R 2.5<8a41>2.5 G 2.5(nI)
+383.99 60 S(nter)395.94 60 Q(netw)-.15 E(ork Mail Router)-.1 E/F1 10
+/Times-Roman@0 SF .632(arbitrary address syntax)72 96 R .633(es, resolving amb\
+iguities using heuristics speci\214ed by the system administrator)-.15 F 3.133
+(,a)-.4 G(s)500.11 96 Q .348(well as domain-based addressing.)72 108 R .347
+(It helps guide the con)5.347 F -.15(ve)-.4 G .347
+(rsion of message formats between disparate net-).15 F -.1(wo)72 120 S 3.394
+(rks. In).1 F(short,)3.394 E/F2 10/Times-Italic@0 SF(sendmail)3.394 E F1 .894
+(is designed to assist a graceful transition to consistent internetw)3.394 F
+.895(ork addressing)-.1 F(schemes.)72 132 Q .153
+(Section 1 discusses the design goals for)97 160.2 R F2(sendmail)2.653 E F1
+5.153(.S)C .152(ection 2 gi)308.214 160.2 R -.15(ve)-.25 G 2.652(sa).15 G 2.652
+(no)370.76 160.2 S -.15(ve)383.262 160.2 S(rvie).15 E 2.652(wo)-.25 G 2.652(ft)
+422.724 160.2 S .152(he basic functions)431.486 160.2 R .644(of the system.)72
+172.2 R .644(In section 3, details of usage are discussed.)5.644 F .644
+(Section 4 compares)5.644 F F2(sendmail)3.144 E F1 .645(to other internet)3.144
+F(mail routers, and an e)72 184.2 Q -.25(va)-.25 G(luation of).25 E F2
+(sendmail)2.5 E F1(is gi)2.5 E -.15(ve)-.25 G 2.5(ni).15 G 2.5(ns)283.3 184.2 S
+(ection 5, including future plans.)294.69 184.2 Q F0 2.5(1. DESIGN)72 208.2 R
+(GO)2.5 E(ALS)-.4 E F1(Design goals for)112 224.4 Q F2(sendmail)2.5 E F1
+(include:)2.5 E 12.5(\(1\) Compatibility)92 240.6 R 1.363(with the e)3.864 F
+1.363(xisting mail programs, including Bell v)-.15 F 1.363
+(ersion 6 mail, Bell v)-.15 F 1.363(ersion 7)-.15 F 1.202(mail [UNIX83], Berk)
+118.66 252.6 R(ele)-.1 E(y)-.15 E F2(Mail)3.702 E F1 1.202
+([Shoens79], BerkNet mail [Schmidt79], and hopefully UUCP)3.702 F(mail [No)
+118.66 264.6 Q(witz78a, No)-.25 E 2.5(witz78b]. ARP)-.25 F(ANET mail [Crock)
+-.92 E(er77a, Postel77] w)-.1 E(as also required.)-.1 E 12.5(\(2\) Reliability)
+92 280.8 R 4.003(,i)-.65 G 4.003(nt)169.523 280.8 S 1.502
+(he sense of guaranteeing that e)181.306 280.8 R -.15(ve)-.25 G 1.502
+(ry message is correctly deli).15 F -.15(ve)-.25 G 1.502(red or at least).15 F
+.368
+(brought to the attention of a human for correct disposal; no message should e)
+118.66 292.8 R -.15(ve)-.25 G 2.868(rb).15 G 2.868(ec)452.252 292.8 S
+(ompletely)464 292.8 Q 2.541(lost. This)118.66 304.8 R .041(goal w)2.541 F .041
+(as considered essential because of the emphasis on mail in our en)-.1 F 2.54
+(vironment. It)-.4 F 1.754
+(has turned out to be one of the hardest goals to satisfy)118.66 316.8 R 4.255
+(,e)-.65 G 1.755(specially in the f)363.75 316.8 R 1.755(ace of the man)-.1 F
+(y)-.15 E .978(anomalous message formats produced by v)118.66 328.8 R .977
+(arious ARP)-.25 F .977(ANET sites.)-.92 F -.15(Fo)5.977 G 3.477(re).15 G .977
+(xample, certain sites)420.116 328.8 R .069
+(generate improperly formated addresses, occasionally causing error)118.66
+340.8 R .069(-message loops.)-.2 F .069(Some hosts)5.069 F .063(use blanks in \
+names, causing problems with UNIX mail programs that assume that an address is)
+118.66 352.8 R .111(one w)118.66 364.8 R 2.611(ord. The)-.1 F .111
+(semantics of some \214elds are interpreted slightly dif)2.611 F .112
+(ferently by dif)-.25 F .112(ferent sites.)-.25 F(In)5.112 E(summary)118.66
+376.8 Q 3.023(,t)-.65 G .523(he obscure features of the ARP)163.533 376.8 R
+.523(ANET mail protocol really)-.92 F F2(ar)3.023 E(e)-.37 E F1 .522
+(used and are dif)3.023 F(\214cult)-.25 E(to support, b)118.66 388.8 Q
+(ut must be supported.)-.2 E 12.5(\(3\) Existing)92 405 R(softw)2.938 E .438
+(are to do actual deli)-.1 F -.15(ve)-.25 G .439(ry should be used whene).15 F
+-.15(ve)-.25 G 2.939(rp).15 G 2.939(ossible. This)387.654 405 R .439(goal deri)
+2.939 F -.15(ve)-.25 G 2.939(sa).15 G(s)500.11 405 Q
+(much from political and practical considerations as technical.)118.66 417 Q
+12.5(\(4\) Easy)92 433.2 R -.15(ex)2.899 G .399(pansion to f).15 F .399
+(airly comple)-.1 F 2.898(xe)-.15 G -.4(nv)261.064 433.2 S .398
+(ironments, including multiple connections to a single net-).4 F -.1(wo)118.66
+445.2 S .115
+(rk type \(such as with multiple UUCP or Ether nets [Metcalfe76]\).).1 F .115
+(This goal requires consid-)5.115 F .587(eration of the contents of an address\
+ as well as its syntax in order to determine which g)118.66 457.2 R(ate)-.05 E
+-.1(wa)-.25 G(y).1 E 1.018(to use.)118.66 469.2 R -.15(Fo)6.018 G 3.518(re).15
+G 1.018(xample, the ARP)173.354 469.2 R 1.019
+(ANET is bringing up the TCP protocol to replace the old NCP)-.92 F 4.791
+(protocol. No)118.66 481.2 R 2.291(host at Berk)4.791 F(ele)-.1 E 4.791(yr)-.15
+G 2.291(uns both TCP and NCP)256.235 481.2 R 4.791(,s)-1.11 G 4.79(oi)369.37
+481.2 S 4.79(ti)381.94 481.2 S 4.79(sn)392.29 481.2 S 2.29
+(ecessary to look at the)405.97 481.2 R(ARP)118.66 493.2 Q .016
+(ANET host name to determine whether to route mail to an NCP g)-.92 F(ate)-.05
+E -.1(wa)-.25 G 2.517(yo).1 G 2.517(raT)435.569 493.2 S .017(CP g)454.483 493.2
+R(ate)-.05 E -.1(wa)-.25 G -.65(y.).1 G 12.5(\(5\) Con\214guration)92 509.4 R
+.145(should not be compiled into the code.)2.645 F 2.645(As)5.145 G .145
+(ingle compiled program should be able)346.905 509.4 R .91(to run as is at an)
+118.66 521.4 R 3.41(ys)-.15 G .91
+(ite \(barring such basic changes as the CPU type or the operating system\).)
+200.63 521.4 R 2.61 -.8(We h)118.66 533.4 T -2.25 -.2(av e).8 H 1.009
+(found this seemingly unimportant goal to be critical in real life.)3.71 F
+1.009(Besides the simple)6.009 F .66(problems that occur when an)118.66 545.4 R
+3.16(yp)-.15 G .66(rogram gets recompiled in a dif)249.84 545.4 R .66
+(ferent en)-.25 F .66(vironment, man)-.4 F 3.16(ys)-.15 G(ites)490.11 545.4 Q
+(lik)118.66 557.4 Q 2.5(et)-.1 G 2.5<6f99>138.84 557.4 S(\214ddle\232 with an)
+150.78 557.4 Q(ything that the)-.15 E 2.5(yw)-.15 G(ill be recompiling an)
+282.42 557.4 Q(yw)-.15 E(ay)-.1 E(.)-.65 E(\(6\))92 573.6 Q F2(Sendmail)118.66
+573.6 Q F1 .184(must be able to let v)2.684 F .184
+(arious groups maintain their o)-.25 F .184(wn mailing lists, and let indi)-.25
+F(viduals)-.25 E(specify their o)118.66 585.6 Q(wn forw)-.25 E
+(arding, without modifying the system alias \214le.)-.1 E 12.5(\(7\) Each)92
+601.8 R .313(user should be able to specify which mailer to e)2.813 F -.15(xe)
+-.15 G .313(cute to process mail being deli).15 F -.15(ve)-.25 G .314(red for)
+.15 F 3.098(him. This)118.66 613.8 R .598(feature allo)3.098 F .598
+(ws users who are using specialized mailers that use a dif)-.25 F .598
+(ferent format to)-.25 F -.2(bu)118.66 625.8 S .25(ild their en).2 F .25
+(vironment without changing the system, and f)-.4 F .25
+(acilitates specialized functions \(such)-.1 F(as returning an \231I am on v)
+118.66 637.8 Q(acation\232 message\).)-.25 E 12.5(\(8\) Netw)92 654 R 1.553
+(ork traf)-.1 F 1.552(\214c should be minimized by batching addresses to a sin\
+gle host where possible,)-.25 F(without assistance from the user)118.66 666 Q
+(.)-.55 E .374(These goals moti)112 682.2 R -.25(va)-.25 G .374
+(ted the architecture illustrated in \214gure 1.).25 F .375
+(The user interacts with a mail gen-)5.375 F .491(erating and sending program.)
+87 694.2 R .491(When the mail is created, the generator calls)5.491 F F2
+(sendmail)2.99 E F1 2.99(,w)C .49(hich routes the)444.14 694.2 R .84
+(message to the correct mailer\(s\).)87 706.2 R .841
+(Since some of the senders may be netw)5.84 F .841(ork serv)-.1 F .841
+(ers and some of the)-.15 F(mailers may be netw)87 718.2 Q(ork clients,)-.1 E
+F2(sendmail)2.5 E F1(may be used as an internet mail g)2.5 E(ate)-.05 E -.1(wa)
+-.25 G -.65(y.).1 G EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-3)462.9 60 Q .4 LW 77 108 72 108 DL 79 108 74 108
+DL 84 108 79 108 DL 89 108 84 108 DL 94 108 89 108 DL 99 108 94 108 DL 104 108
+99 108 DL 109 108 104 108 DL 114 108 109 108 DL 119 108 114 108 DL 124 108 119
+108 DL 129 108 124 108 DL 134 108 129 108 DL 139 108 134 108 DL 144 108 139 108
+DL 149 108 144 108 DL 154 108 149 108 DL 159 108 154 108 DL 164 108 159 108 DL
+169 108 164 108 DL 174 108 169 108 DL 179 108 174 108 DL 184 108 179 108 DL 189
+108 184 108 DL 194 108 189 108 DL 199 108 194 108 DL 204 108 199 108 DL 209 108
+204 108 DL 214 108 209 108 DL 219 108 214 108 DL 224 108 219 108 DL 229 108 224
+108 DL 234 108 229 108 DL 239 108 234 108 DL 244 108 239 108 DL 249 108 244 108
+DL 254 108 249 108 DL 259 108 254 108 DL 264 108 259 108 DL 269 108 264 108 DL
+274 108 269 108 DL 279 108 274 108 DL 284 108 279 108 DL 289 108 284 108 DL 294
+108 289 108 DL 299 108 294 108 DL 304 108 299 108 DL 309 108 304 108 DL 314 108
+309 108 DL 319 108 314 108 DL 324 108 319 108 DL 329 108 324 108 DL 334 108 329
+108 DL 339 108 334 108 DL 344 108 339 108 DL 349 108 344 108 DL 354 108 349 108
+DL 359 108 354 108 DL 364 108 359 108 DL 369 108 364 108 DL 374 108 369 108 DL
+379 108 374 108 DL 384 108 379 108 DL 389 108 384 108 DL 394 108 389 108 DL 399
+108 394 108 DL 404 108 399 108 DL 409 108 404 108 DL 414 108 409 108 DL 419 108
+414 108 DL 424 108 419 108 DL 429 108 424 108 DL 434 108 429 108 DL 439 108 434
+108 DL 444 108 439 108 DL 449 108 444 108 DL 454 108 449 108 DL 459 108 454 108
+DL 464 108 459 108 DL 469 108 464 108 DL 474 108 469 108 DL 479 108 474 108 DL
+484 108 479 108 DL 489 108 484 108 DL 494 108 489 108 DL 499 108 494 108 DL 504
+108 499 108 DL/F1 10/Times-Roman@0 SF(sender1)164.45 155.6 Q 144 135.6 144
+171.6 DL 216 135.6 144 135.6 DL 216 171.6 216 135.6 DL 144 171.6 216 171.6 DL
+(sender2)272.45 155.6 Q 252 135.6 252 171.6 DL 324 135.6 252 135.6 DL 324 171.6
+324 135.6 DL 252 171.6 324 171.6 DL(sender3)380.45 155.6 Q 360 135.6 360 171.6
+DL 432 135.6 360 135.6 DL 432 171.6 432 135.6 DL 360 171.6 432 171.6 DL 288
+207.6 288 171.6 DL 288 207.6 286.2 200.4 DL 288 207.6 289.8 200.4 DL(sendmail)
+269.945 227.6 Q 216 207.6 216 243.6 DL 360 207.6 216 207.6 DL 360 243.6 360
+207.6 DL 216 243.6 360 243.6 DL 288 279.6 288 243.6 DL 288 279.6 286.2 272.4 DL
+288 279.6 289.8 272.4 DL(mailer1)164.725 299.6 Q 144 279.6 144 315.6 DL 216
+279.6 144 279.6 DL 216 315.6 216 279.6 DL 144 315.6 216 315.6 DL(mailer2)
+272.725 299.6 Q 252 279.6 252 315.6 DL 324 279.6 252 279.6 DL 324 315.6 324
+279.6 DL 252 315.6 324 315.6 DL(mailer3)380.725 299.6 Q 360 279.6 360 315.6 DL
+432 279.6 360 279.6 DL 432 315.6 432 279.6 DL 360 315.6 432 315.6 DL 252 207.6
+180 171.6 DL 252 207.6 244.728 206.016 DL 252 207.6 246.384 202.776 DL 324
+207.6 396 171.6 DL 324 207.6 329.616 202.776 DL 324 207.6 331.272 206.016 DL
+180 279.6 252 243.6 DL 180 279.6 185.616 274.776 DL 180 279.6 187.272 278.016
+DL 396 279.6 324 243.6 DL 396 279.6 388.728 278.016 DL 396 279.6 390.384
+274.776 DL(Figure 1 \212 Sendmail System Structure.)208 346.8 Q 77 358.8 72
+358.8 DL 79 358.8 74 358.8 DL 84 358.8 79 358.8 DL 89 358.8 84 358.8 DL 94
+358.8 89 358.8 DL 99 358.8 94 358.8 DL 104 358.8 99 358.8 DL 109 358.8 104
+358.8 DL 114 358.8 109 358.8 DL 119 358.8 114 358.8 DL 124 358.8 119 358.8 DL
+129 358.8 124 358.8 DL 134 358.8 129 358.8 DL 139 358.8 134 358.8 DL 144 358.8
+139 358.8 DL 149 358.8 144 358.8 DL 154 358.8 149 358.8 DL 159 358.8 154 358.8
+DL 164 358.8 159 358.8 DL 169 358.8 164 358.8 DL 174 358.8 169 358.8 DL 179
+358.8 174 358.8 DL 184 358.8 179 358.8 DL 189 358.8 184 358.8 DL 194 358.8 189
+358.8 DL 199 358.8 194 358.8 DL 204 358.8 199 358.8 DL 209 358.8 204 358.8 DL
+214 358.8 209 358.8 DL 219 358.8 214 358.8 DL 224 358.8 219 358.8 DL 229 358.8
+224 358.8 DL 234 358.8 229 358.8 DL 239 358.8 234 358.8 DL 244 358.8 239 358.8
+DL 249 358.8 244 358.8 DL 254 358.8 249 358.8 DL 259 358.8 254 358.8 DL 264
+358.8 259 358.8 DL 269 358.8 264 358.8 DL 274 358.8 269 358.8 DL 279 358.8 274
+358.8 DL 284 358.8 279 358.8 DL 289 358.8 284 358.8 DL 294 358.8 289 358.8 DL
+299 358.8 294 358.8 DL 304 358.8 299 358.8 DL 309 358.8 304 358.8 DL 314 358.8
+309 358.8 DL 319 358.8 314 358.8 DL 324 358.8 319 358.8 DL 329 358.8 324 358.8
+DL 334 358.8 329 358.8 DL 339 358.8 334 358.8 DL 344 358.8 339 358.8 DL 349
+358.8 344 358.8 DL 354 358.8 349 358.8 DL 359 358.8 354 358.8 DL 364 358.8 359
+358.8 DL 369 358.8 364 358.8 DL 374 358.8 369 358.8 DL 379 358.8 374 358.8 DL
+384 358.8 379 358.8 DL 389 358.8 384 358.8 DL 394 358.8 389 358.8 DL 399 358.8
+394 358.8 DL 404 358.8 399 358.8 DL 409 358.8 404 358.8 DL 414 358.8 409 358.8
+DL 419 358.8 414 358.8 DL 424 358.8 419 358.8 DL 429 358.8 424 358.8 DL 434
+358.8 429 358.8 DL 439 358.8 434 358.8 DL 444 358.8 439 358.8 DL 449 358.8 444
+358.8 DL 454 358.8 449 358.8 DL 459 358.8 454 358.8 DL 464 358.8 459 358.8 DL
+469 358.8 464 358.8 DL 474 358.8 469 358.8 DL 479 358.8 474 358.8 DL 484 358.8
+479 358.8 DL 489 358.8 484 358.8 DL 494 358.8 489 358.8 DL 499 358.8 494 358.8
+DL 504 358.8 499 358.8 DL F0 2.5(2. O)72 394.8 R(VER)-.5 E(VIEW)-.55 E 2.5
+(2.1. System)87 418.8 R(Or)2.5 E(ganization)-.1 E/F2 10/Times-Italic@0 SF
+(Sendmail)127 435 Q F1 .874(neither interf)3.374 F .874
+(aces with the user nor does actual mail deli)-.1 F -.15(ve)-.25 G(ry).15 E
+5.873(.R)-.65 G(ather)431.241 435 Q 3.373(,i)-.4 G 3.373(tc)459.484 435 S .873
+(ollects a)470.077 435 R .619(message generated by a user interf)102 447 R .619
+(ace program \(UIP\) such as Berk)-.1 F(ele)-.1 E(y)-.15 E F2(Mail)3.12 E F1
+3.12(,M)C 3.12(S[)427.6 447 S(Crock)439.61 447 Q .62(er77b], or)-.1 F 1.428
+(MH [Borden79], edits the message as required by the destination netw)102 459 R
+1.427(ork, and calls appropriate)-.1 F .28(mailers to do mail deli)102 473 R
+-.15(ve)-.25 G .281(ry or queueing for netw).15 F .281(ork transmission)-.1 F
+/F3 7/Times-Roman@0 SF(1)364.275 469 Q F1 5.281(.T)367.775 473 S .281
+(his discipline allo)381.666 473 R .281(ws the inser)-.25 F(-)-.2 E 1.354
+(tion of ne)102 485 R 3.854(wm)-.25 G 1.354(ailers at minimum cost.)161.642 485
+R 1.354(In this sense)6.354 F F2(sendmail)3.853 E F1 1.353
+(resembles the Message Processing)3.853 F(Module \(MPM\) of [Postel79b].)102
+497 Q F0 2.5(2.2. Interfaces)87 521 R(to the Outside W)2.5 E(orld)-.75 E F1
+.041(There are three w)127 537.2 R(ays)-.1 E F2(sendmail)2.541 E F1 .041
+(can communicate with the outside w)2.541 F .042(orld, both in recei)-.1 F .042
+(ving and)-.25 F 1.195(in sending mail.)102 549.2 R 1.194
+(These are using the con)6.194 F -.15(ve)-.4 G 1.194(ntional UNIX ar).15 F
+1.194(gument v)-.18 F 1.194(ector/return status, speaking)-.15 F(SMTP o)102
+561.2 Q -.15(ve)-.15 G 2.5(rap).15 G(air of UNIX pipes, and speaking SMTP o)
+162.53 561.2 Q -.15(ve)-.15 G 2.5(ra).15 G 2.5(ni)348.03 561.2 S
+(nterprocess\(or\) channel.)358.31 561.2 Q F0 2.5(2.2.1. Ar)102 585.2 R
+(gument v)-.1 E(ector/exit status)-.1 E F1 .52(This technique is the standard \
+UNIX method for communicating with the process.)142 601.4 R 3.02(Al)5.52 G(ist)
+494.55 601.4 Q .442(of recipients is sent in the ar)117 613.4 R .441(gument v)
+-.18 F(ector)-.15 E 2.941(,a)-.4 G .441
+(nd the message body is sent on the standard input.)299.491 613.4 R(An)117
+625.4 Q .351(ything that the mailer prints is simply collected and sent back t\
+o the sender if there were an)-.15 F(y)-.15 E 2.621(problems. The)117 637.4 R
+-.15(ex)2.621 G .121(it status from the mailer is collected after the message \
+is sent, and a diagnostic).15 F(is printed if appropriate.)117 649.4 Q .32 LW
+76 678.8 72 678.8 DL 80 678.8 76 678.8 DL 84 678.8 80 678.8 DL 88 678.8 84
+678.8 DL 92 678.8 88 678.8 DL 96 678.8 92 678.8 DL 100 678.8 96 678.8 DL 104
+678.8 100 678.8 DL 108 678.8 104 678.8 DL 112 678.8 108 678.8 DL 116 678.8 112
+678.8 DL 120 678.8 116 678.8 DL 124 678.8 120 678.8 DL 128 678.8 124 678.8 DL
+132 678.8 128 678.8 DL 136 678.8 132 678.8 DL 140 678.8 136 678.8 DL 144 678.8
+140 678.8 DL 148 678.8 144 678.8 DL 152 678.8 148 678.8 DL 156 678.8 152 678.8
+DL 160 678.8 156 678.8 DL 164 678.8 160 678.8 DL 168 678.8 164 678.8 DL 172
+678.8 168 678.8 DL 176 678.8 172 678.8 DL 180 678.8 176 678.8 DL 184 678.8 180
+678.8 DL 188 678.8 184 678.8 DL 192 678.8 188 678.8 DL 196 678.8 192 678.8 DL
+200 678.8 196 678.8 DL 204 678.8 200 678.8 DL 208 678.8 204 678.8 DL 212 678.8
+208 678.8 DL 216 678.8 212 678.8 DL/F4 5/Times-Roman@0 SF(1)93.6 689.2 Q/F5 8
+/Times-Roman@0 SF -.12(ex)3.2 K(cept when mailing to a \214le, when).12 E/F6 8
+/Times-Italic@0 SF(sendmail)2 E F5(does the deli)2 E -.12(ve)-.2 G(ry directly)
+.12 E(.)-.52 E EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 192.28(SMM:9-4 SENDMAIL)72 60 R 2.5<8a41>2.5 G 2.5(nI)
+383.99 60 S(nter)395.94 60 Q(netw)-.15 E(ork Mail Router)-.1 E 2.5(2.2.2. SMTP)
+102 96 R -.1(ove)2.5 G 2.5(rp).1 G(ipes)186.52 96 Q/F1 10/Times-Roman@0 SF .774
+(The SMTP protocol [Postel82] can be used to run an interacti)142 112.2 R 1.074
+-.15(ve l)-.25 H .774(ock-step interf).15 F .774(ace with)-.1 F .507
+(the mailer)117 124.2 R 5.507(.A)-.55 G .506(subprocess is still created, b)
+175.461 124.2 R .506(ut no recipient addresses are passed to the mailer via)-.2
+F .075(the ar)117 136.2 R .075(gument list.)-.18 F .075(Instead, the)5.075 F
+2.575(ya)-.15 G .075
+(re passed one at a time in commands sent to the processes stan-)249.805 136.2
+R .19(dard input.)117 148.2 R(An)5.19 E .19(ything appearing on the standard o\
+utput must be a reply code in a special format.)-.15 F F0 2.5(2.2.3. SMTP)102
+172.2 R -.1(ove)2.5 G 2.5(ra).1 G 2.5(nI)185.96 172.2 S(PC connection)197.91
+172.2 Q F1 .366(This technique is similar to the pre)142 188.4 R .366
+(vious technique, e)-.25 F .366(xcept that it uses a 4.2bsd IPC chan-)-.15 F
+.953(nel [UNIX83].)117 200.4 R .953(This method is e)5.953 F .953
+(xceptionally \215e)-.15 F .952
+(xible in that the mailer need not reside on the)-.15 F(same machine.)117 212.4
+Q(It is normally used to connect to a sendmail process on another machine.)5 E
+F0 2.5(2.3. Operational)87 236.4 R(Description)2.5 E F1 .228(When a sender w)
+127 252.6 R .228(ants to send a message, it issues a request to)-.1 F/F2 10
+/Times-Italic@0 SF(sendmail)2.729 E F1 .229(using one of the three)2.729 F
+1.028(methods described abo)102 264.6 R -.15(ve)-.15 G(.).15 E F2(Sendmail)
+6.028 E F1 1.028(operates in tw)3.528 F 3.528(od)-.1 G 1.028(istinct phases.)
+325.706 264.6 R 1.028(In the \214rst phase, it collects)6.028 F .612
+(and stores the message.)102 276.6 R .612(In the second phase, message deli)
+5.612 F -.15(ve)-.25 G .612(ry occurs.).15 F .612(If there were errors during)
+5.612 F 1.59(processing during the second phase,)102 288.6 R F2(sendmail)4.09 E
+F1 1.59(creates and returns a ne)4.09 F 4.09(wm)-.25 G 1.59
+(essage describing the)415.84 288.6 R
+(error and/or returns an status code telling what went wrong.)102 300.6 Q F0
+2.5(2.3.1. Ar)102 324.6 R(gument pr)-.1 E(ocessing and addr)-.18 E(ess parsing)
+-.18 E F1(If)142 340.8 Q F2(sendmail)3.321 E F1 .821
+(is called using one of the tw)3.321 F 3.322(os)-.1 G .822
+(ubprocess techniques, the ar)320.66 340.8 R .822(guments are \214rst)-.18 F
+.797(scanned and option speci\214cations are processed.)117 352.8 R .796
+(Recipient addresses are then collected, either)5.796 F .717(from the command \
+line or from the SMTP RCPT command, and a list of recipients is created.)117
+364.8 R .347(Aliases are e)117 376.8 R .347
+(xpanded at this step, including mailing lists.)-.15 F .347(As much v)5.347 F
+.346(alidation as possible of the)-.25 F 1.001
+(addresses is done at this step: syntax is check)117 388.8 R 1.002
+(ed, and local addresses are v)-.1 F 1.002(eri\214ed, b)-.15 F 1.002
+(ut detailed)-.2 F .709
+(checking of host names and addresses is deferred until deli)117 400.8 R -.15
+(ve)-.25 G(ry).15 E 5.708(.F)-.65 G(orw)388.946 400.8 Q .708
+(arding is also performed)-.1 F(as the local addresses are v)117 412.8 Q
+(eri\214ed.)-.15 E F2(Sendmail)142 429 Q F1 .307
+(appends each address to the recipient list after parsing.)2.807 F .307
+(When a name is aliased)5.307 F .322(or forw)117 441 R .322(arded, the old nam\
+e is retained in the list, and a \215ag is set that tells the deli)-.1 F -.15
+(ve)-.25 G .322(ry phase to).15 F .479(ignore this recipient.)117 453 R .479
+(This list is k)5.479 F .479(ept free from duplicates, pre)-.1 F -.15(ve)-.25 G
+.48(nting alias loops and duplicate).15 F(messages deli)117 465 Q -.15(ve)-.25
+G(rd to the same recipient, as might occur if a person is in tw).15 E 2.5(og)
+-.1 G(roups.)428.12 465 Q F0 2.5(2.3.2. Message)102 489 R(collection)2.5 E F2
+(Sendmail)142 505.2 Q F1 .454(then collects the message.)2.954 F .454
+(The message should ha)5.454 F .754 -.15(ve a h)-.2 H .453(eader at the be).15
+F(ginning.)-.15 E .778(No formatting requirements are imposed on the message e)
+117 517.2 R .778(xcept that the)-.15 F 3.278(ym)-.15 G .778(ust be lines of te)
+427.708 517.2 R(xt)-.15 E .78(\(i.e., binary data is not allo)117 529.2 R 3.28
+(wed\). The)-.25 F .779(header is parsed and stored in memory)3.28 F 3.279(,a)
+-.65 G .779(nd the body of)443.613 529.2 R(the message is sa)117 541.2 Q -.15
+(ve)-.2 G 2.5(di).15 G 2.5(nat)204.97 541.2 S(emporary \214le.)222.19 541.2 Q
+3.227 -.8(To s)142 557.4 T 1.627(implify the program interf).8 F 1.628
+(ace, the message is collected e)-.1 F -.15(ve)-.25 G 4.128(ni).15 G 4.128(fn)
+420.536 557.4 S 4.128(oa)432.994 557.4 S 1.628(ddresses were)446.562 557.4 R
+-.25(va)117 569.4 S 2.5(lid. The).25 F(message will be returned with an error)
+2.5 E(.)-.55 E F0 2.5(2.3.3. Message)102 593.4 R(deli)2.5 E -.1(ve)-.1 G(ry).1
+E F1 -.15(Fo)142 609.6 S 2.618(re).15 G .117
+(ach unique mailer and host in the recipient list,)162.798 609.6 R F2(sendmail)
+2.617 E F1 .117(calls the appropriate mailer)2.617 F(.)-.55 E .619
+(Each mailer in)117 621.6 R -.2(vo)-.4 G .619(cation sends to all users recei)
+.2 F .619(ving the message on one host.)-.25 F .62(Mailers that only)5.62 F
+(accept one recipient at a time are handled properly)117 633.6 Q(.)-.65 E .47
+(The message is sent to the mailer using one of the same three interf)142 649.8
+R .47(aces used to submit a)-.1 F 1.465(message to sendmail.)117 661.8 R 1.465
+(Each cop)6.465 F 3.965(yo)-.1 G 3.965(ft)263.925 661.8 S 1.465
+(he message is prepended by a customized header)274 661.8 R 6.465(.T)-.55 G(he)
+494.56 661.8 Q 1.455(mailer status code is caught and check)117 673.8 R 1.455
+(ed, and a suitable error message gi)-.1 F -.15(ve)-.25 G 3.955(na).15 G 3.955
+(sa)448.115 673.8 S(ppropriate.)460.4 673.8 Q .589(The e)117 685.8 R .589(xit \
+code must conform to a system standard or a generic message \(\231Service una)
+-.15 F -.25(va)-.2 G(ilable\232\)).25 E(is gi)117 697.8 Q -.15(ve)-.25 G(n.).15
+E EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-5)462.9 60 Q 2.5(2.3.4. Queueing)102 96 R -.25(fo)
+2.5 G 2.5(rr).25 G(etransmission)192.4 96 Q/F1 10/Times-Roman@0 SF .209(If the\
+ mailer returned an status that indicated that it might be able to handle the \
+mail later)142 112.2 R(,)-.4 E/F2 10/Times-Italic@0 SF(sendmail)117 124.2 Q F1
+(will queue the mail and try ag)2.5 E(ain later)-.05 E(.)-.55 E F0 2.5
+(2.3.5. Retur)102 148.2 R 2.5(nt)-.15 G 2.5(os)165.73 148.2 S(ender)177.12
+148.2 Q F1 .588(If errors occur during processing,)142 164.4 R F2(sendmail)
+3.088 E F1 .589(returns the message to the sender for retrans-)3.088 F 3.133
+(mission. The)117 176.4 R .632(letter can be mailed back or written in the \
+\214le \231dead.letter\232 in the sender')3.133 F 3.132(sh)-.55 G(ome)486.78
+176.4 Q(directory)117 190.4 Q/F3 7/Times-Roman@0 SF(2)153.1 186.4 Q F1(.)156.6
+190.4 Q F0 2.5(2.4. Message)87 214.4 R(Header Editing)2.5 E F1 1.756
+(Certain editing of the message header occurs automatically)127 230.6 R 6.756
+(.H)-.65 G 1.756(eader lines can be inserted)391.456 230.6 R .41
+(under control of the con\214guration \214le.)102 242.6 R .41
+(Some lines can be mer)5.41 F .41(ged; for e)-.18 F .41
+(xample, a \231From:\232 line and)-.15 F 2.5<6199>102 254.6 S
+(Full-name:\232 line can be mer)113.38 254.6 Q
+(ged under certain circumstances.)-.18 E F0 2.5(2.5. Con\214guration)87 278.6 R
+(File)2.5 E F1 .798(Almost all con\214guration information is read at runtime \
+from an ASCII \214le, encoding macro)127 294.8 R .679
+(de\214nitions \(de\214ning the v)102 306.8 R .678
+(alue of macros used internally\), header declarations \(telling sendmail the)
+-.25 F 1.009(format of header lines that it will process specially)102 318.8 R
+3.509(,i)-.65 G 1.009(.e., lines that it will add or reformat\), mailer)320.398
+318.8 R .478(de\214nitions \(gi)102 330.8 R .478(ving information such as the \
+location and characteristics of each mailer\), and address)-.25 F(re)102 342.8
+Q .428(writing rules \(a limited production system to re)-.25 F .429
+(write addresses which is used to parse and re)-.25 F(write)-.25 E
+(the addresses\).)102 354.8 Q 2.828 -.8(To i)127 371 T(mpro).8 E 1.528 -.15
+(ve p)-.15 H 1.228(erformance when reading the con\214guration \214le, a memor\
+y image can be pro-).15 F 2.5(vided. This)102 383 R(pro)2.5 E
+(vides a \231compiled\232 form of the con\214guration \214le.)-.15 E F0 2.5
+(3. USA)72 407 R(GE AND IMPLEMENT)-.55 E -.95(AT)-.9 G(ION).95 E 2.5(3.1. Ar)87
+431 R(guments)-.1 E F1(Ar)127 447.2 Q .376
+(guments may be \215ags and addresses.)-.18 F .377(Flags set v)5.377 F .377
+(arious processing options.)-.25 F -.15(Fo)5.377 G(llo).15 E .377(wing \215ag)
+-.25 F(ar)102 459.2 Q .281(guments, address ar)-.18 F .281(guments may be gi)
+-.18 F -.15(ve)-.25 G .281(n, unless we are running in SMTP mode.).15 F .28
+(Addresses fol-)5.28 F(lo)102 471.2 Q 2.5(wt)-.25 G(he syntax in RFC822 [Crock)
+122.03 471.2 Q(er82] for ARP)-.1 E(ANET address formats.)-.92 E
+(In brief, the format is:)5 E 12.5(\(1\) An)107 487.4 R
+(ything in parentheses is thro)-.15 E(wn a)-.25 E -.1(wa)-.15 G 2.5(y\().1 G
+(as a comment\).)299.65 487.4 Q 12.5(\(2\) An)107 503.6 R .051
+(ything in angle brack)-.15 F .051(ets \(\231<)-.1 F .051
+(>\232\) is preferred o)1.666 F -.15(ve)-.15 G 2.551(ra).15 G -.15(ny)348.064
+503.6 S .051(thing else.).15 F .051(This rule implements the)5.051 F(ARP)133.66
+515.6 Q(ANET standard that addresses of the form)-.92 E
+(user name <machine-address>)173.66 531.8 Q(will send to the electronic \231ma\
+chine-address\232 rather than the human \231user name.)133.66 548 Q<9a>-.7 E
+12.5(\(3\) Double)107 564.2 R 2.246(quotes \()4.746 F -2.754 2.5("\) q)2.5 H
+2.246(uote phrases; backslashes quote characters.)224.188 564.2 R 2.246
+(Backslashes are more)7.246 F(po)133.66 576.2 Q .654(werful in that the)-.25 F
+3.154(yw)-.15 G .655(ill cause otherwise equi)229.196 576.2 R -.25(va)-.25 G
+.655(lent phrases to compare dif).25 F .655(ferently \212 for)-.25 F -.15(ex)
+133.66 588.2 S(ample,).15 E F2(user)2.5 E F1(and)2.5 E F2("user")2.5 E F1
+(are equi)2.5 E -.25(va)-.25 G(lent, b).25 E(ut)-.2 E F2(\\user)2.5 E F1
+(is dif)2.5 E(ferent from either of them.)-.25 E -.15(Pa)127 604.4 S 1.12
+(rentheses, angle brack).15 F 1.12
+(ets, and double quotes must be properly balanced and nested.)-.1 F(The)6.12 E
+(re)102 618.4 Q(writing rules control remaining parsing)-.25 E F3(3)266.17
+614.4 Q F1(.)269.67 618.4 Q .32 LW 76 646 72 646 DL 80 646 76 646 DL 84 646 80
+646 DL 88 646 84 646 DL 92 646 88 646 DL 96 646 92 646 DL 100 646 96 646 DL 104
+646 100 646 DL 108 646 104 646 DL 112 646 108 646 DL 116 646 112 646 DL 120 646
+116 646 DL 124 646 120 646 DL 128 646 124 646 DL 132 646 128 646 DL 136 646 132
+646 DL 140 646 136 646 DL 144 646 140 646 DL 148 646 144 646 DL 152 646 148 646
+DL 156 646 152 646 DL 160 646 156 646 DL 164 646 160 646 DL 168 646 164 646 DL
+172 646 168 646 DL 176 646 172 646 DL 180 646 176 646 DL 184 646 180 646 DL 188
+646 184 646 DL 192 646 188 646 DL 196 646 192 646 DL 200 646 196 646 DL 204 646
+200 646 DL 208 646 204 646 DL 212 646 208 646 DL 216 646 212 646 DL/F4 5
+/Times-Roman@0 SF(2)93.6 656.4 Q/F5 8/Times-Roman@0 SF(Ob)3.2 I(viously)-.12 E
+2.226(,i)-.52 G 2.226(ft)135.246 659.6 S .226(he site gi)142.36 659.6 R .226(v\
+ing the error is not the originating site, the only reasonable option is to ma\
+il back to the sender)-.2 F 4.227(.A)-.44 G(lso,)492.664 659.6 Q .191
+(there are man)72 669.2 R 2.191(ym)-.12 G .19(ore error disposition options, b)
+128.213 669.2 R .19(ut the)-.16 F 2.19(yo)-.12 G .19(nly ef)255.514 669.2 R .19
+(fect the error message \212 the \231return to sender\232 function is al)-.2 F
+-.08(wa)-.08 G .19(ys han-).08 F(dled in one of these tw)72 678.8 Q 2(ow)-.08 G
+(ays.)156.272 678.8 Q F4(3)93.6 689.2 Q F5
+(Disclaimer: Some special processing is done after re)3.2 I
+(writing local names; see belo)-.2 E -.52(w.)-.2 G EP
+%%Page: 6 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 192.28(SMM:9-6 SENDMAIL)72 60 R 2.5<8a41>2.5 G 2.5(nI)
+383.99 60 S(nter)395.94 60 Q(netw)-.15 E(ork Mail Router)-.1 E 2.5(3.2. Mail)87
+96 R(to Files and Pr)2.5 E(ograms)-.18 E/F1 10/Times-Roman@0 SF .609
+(Files and programs are le)127 112.2 R .609(gitimate message recipients.)-.15 F
+.609(Files pro)5.609 F .609(vide archi)-.15 F -.25(va)-.25 G 3.109(ls).25 G .61
+(torage of mes-)445.02 112.2 R .124
+(sages, useful for project administration and history)102 124.2 R 5.124(.P)-.65
+G .124(rograms are useful as recipients in a v)318.308 124.2 R .124(ariety of)
+-.25 F .69(situations, for e)102 136.2 R .691(xample, to maintain a public rep\
+ository of systems messages \(such as the Berk)-.15 F(ele)-.1 E(y)-.15 E/F2 10
+/Times-Italic@0 SF(msgs)102 148.2 Q F1(program, or the MARS system [Sattle)2.5
+E(y78]\).)-.15 E(An)127 164.4 Q 3.188(ya)-.15 G .688(ddress passing through th\
+e initial parsing algorithm as a local address \(i.e, not appear)151.698 164.4
+R(-)-.2 E .276(ing to be a v)102 176.4 R .276
+(alid address for another mailer\) is scanned for tw)-.25 F 2.776(os)-.1 G .277
+(pecial cases.)362.128 176.4 R .277(If pre\214x)5.277 F .277(ed by a v)-.15 F
+(erti-)-.15 E .18(cal bar \(\231)102 188.4 R .833<7c9a>.833 G 2.68(\)t)-.833 G
+.179(he rest of the address is processed as a shell command.)156.456 188.4 R
+.179(If the user name be)5.179 F .179(gins with a)-.15 F(slash mark \(\231/)102
+200.4 Q(\232\) the name is used as a \214le name, instead of a login name.).833
+E .241(Files that ha)127 216.6 R .541 -.15(ve s)-.2 H .241
+(etuid or setgid bits set b).15 F .241(ut no e)-.2 F -.15(xe)-.15 G .241
+(cute bits set ha).15 F .541 -.15(ve t)-.2 H .241(hose bits honored if).15 F F2
+(send-)2.742 E(mail)102 228.6 Q F1(is running as root.)2.5 E F0 2.5
+(3.3. Aliasing,)87 252.6 R -.25(Fo)2.5 G(rwarding, Inclusion).25 E F2(Sendmail)
+127 268.8 Q F1 1.075(reroutes mail three w)3.575 F 3.575(ays. Aliasing)-.1 F
+1.074(applies system wide.)3.575 F -.15(Fo)6.074 G(rw).15 E 1.074(arding allo)
+-.1 F 1.074(ws each)-.25 F .233
+(user to reroute incoming mail destined for that account.)102 280.8 R .233
+(Inclusion directs)5.233 F F2(sendmail)2.733 E F1 .233(to read a \214le for)
+2.733 F 2.5(al)102 292.8 S
+(ist of addresses, and is normally used in conjunction with aliasing.)111.72
+292.8 Q F0 2.5(3.3.1. Aliasing)102 316.8 R F1 1.554
+(Aliasing maps names to address lists using a system-wide \214le.)142 333 R
+1.553(This \214le is inde)6.553 F -.15(xe)-.15 G 4.053(dt).15 G(o)499 333 Q 1.1
+(speed access.)117 345 R 1.101(Only names that parse as local are allo)6.1 F
+1.101(wed as aliases; this guarantees a unique)-.25 F -.1(ke)117 357 S 2.5(y\()
+-.05 G(since there are no nicknames for the local host\).)137.02 357 Q F0 2.5
+(3.3.2. F)102 381 R(orwarding)-.25 E F1 .651
+(After aliasing, recipients that are local and v)142 397.2 R .651
+(alid are check)-.25 F .65(ed for the e)-.1 F .65(xistence of a \231.for)-.15 F
+(-)-.2 E -.1(wa)117 409.2 S .493(rd\232 \214le in their home directory).1 F
+5.493(.I)-.65 G 2.994(fi)264.178 409.2 S 2.994(te)273.282 409.2 S .494
+(xists, the message is)283.346 409.2 R F2(not)2.994 E F1 .494
+(sent to that user)2.994 F 2.994(,b)-.4 G .494(ut rather to)459.132 409.2 R .37
+(the list of users in that \214le.)117 421.2 R .37
+(Often this list will contain only one address, and the feature will be)5.37 F
+(used for netw)117 433.2 Q(ork mail forw)-.1 E(arding.)-.1 E -.15(Fo)142 449.4
+S(rw).15 E 1.151(arding also permits a user to specify a pri)-.1 F -.25(va)-.25
+G 1.152(te incoming mailer).25 F 6.152(.F)-.55 G 1.152(or e)437.346 449.4 R
+1.152(xample, for)-.15 F(-)-.2 E -.1(wa)117 461.4 S(rding to:).1 E -2.5 .833
+("| /)157 477.6 T(usr/local/ne)-.833 E(wmail myname")-.25 E(will use a dif)117
+493.8 Q(ferent incoming mailer)-.25 E(.)-.55 E F0 2.5(3.3.3. Inclusion)102
+517.8 R F1(Inclusion is speci\214ed in RFC 733 [Crock)142 534 Q(er77a] syntax:)
+-.1 E(:Include: pathname)157 550.2 Q .391
+(An address of this form reads the \214le speci\214ed by)117 566.4 R F2
+(pathname)2.891 E F1 .391(and sends to all users listed in that)2.891 F
+(\214le.)117 578.4 Q .644(The intent is)142 594.6 R F2(not)3.144 E F1 .644
+(to support direct use of this feature, b)3.144 F .644
+(ut rather to use this as a subset of)-.2 F 2.5(aliasing. F)117 606.6 R(or e)
+-.15 E(xample, an alias of the form:)-.15 E
+(project: :include:/usr/project/userlist)157 622.8 Q 1.93(is a method of letti\
+ng a project maintain a mailing list without interaction with the system)117
+639 R(administration, e)117 651 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)203.54 651
+S(he alias \214le is protected.)212.15 651 Q 2.024(It is not necessary to reb)
+142 667.2 R 2.024(uild the inde)-.2 F 4.524(xo)-.15 G 4.524(nt)317.822 667.2 S
+2.025(he alias database when a :include: list is)330.126 667.2 R(changed.)117
+679.2 Q EP
+%%Page: 7 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-7)462.9 60 Q 2.5(3.4. Message)87 96 R(Collection)
+2.5 E/F1 10/Times-Roman@0 SF .857
+(Once all recipient addresses are parsed and v)127 112.2 R .857
+(eri\214ed, the message is collected.)-.15 F .856(The message)5.857 F
+(comes in tw)102 124.2 Q 2.5(op)-.1 G
+(arts: a message header and a message body)162.73 124.2 Q 2.5(,s)-.65 G
+(eparated by a blank line.)343.42 124.2 Q
+(The header is formatted as a series of lines of the form)127 140.4 Q
+(\214eld-name: \214eld-v)178 156.6 Q(alue)-.25 E(Field-v)102 172.8 Q 1.366
+(alue can be split across lines by starting the follo)-.25 F 1.366
+(wing lines with a space or a tab)-.25 F 6.366(.S)-.4 G(ome)486.78 172.8 Q .211
+(header \214elds ha)102 184.8 R .511 -.15(ve s)-.2 H .211
+(pecial internal meaning, and ha).15 F .511 -.15(ve a)-.2 H .211
+(ppropriate special processing.).15 F .21(Other headers)5.21 F
+(are simply passed through.)102 196.8 Q
+(Some header \214elds may be added automatically)5 E 2.5(,s)-.65 G
+(uch as time stamps.)413.53 196.8 Q .86(The body is a series of te)127 213 R
+.861(xt lines.)-.15 F .861(It is completely uninterpreted and untouched, e)
+5.861 F .861(xcept that)-.15 F 1.43(lines be)102 225 R 1.43
+(ginning with a dot ha)-.15 F 1.729 -.15(ve t)-.2 H 1.429
+(he dot doubled when transmitted o).15 F -.15(ve)-.15 G 3.929(ra).15 G 3.929
+(nS)407.213 225 S 1.429(MTP channel.)421.702 225 R(This)6.429 E -.15(ex)102 237
+S(tra dot is stripped by the recei).15 E -.15(ve)-.25 G -.55(r.).15 G F0 2.5
+(3.5. Message)87 261 R(Deli)2.5 E -.1(ve)-.1 G(ry).1 E F1 .028
+(The send queue is ordered by recei)127 277.2 R .029
+(ving host before transmission to implement message batch-)-.25 F 3.07
+(ing. Each)102 289.2 R .57(address is mark)3.07 F .57
+(ed as it is sent so rescanning the list is safe.)-.1 F .57(An ar)5.57 F .57
+(gument list is b)-.18 F .57(uilt as)-.2 F 1.138(the scan proceeds.)102 301.2 R
+1.139(Mail to \214les is detected during the scan of the send list.)6.139 F
+1.139(The interf)6.139 F 1.139(ace to the)-.1 F
+(mailer is performed using one of the techniques described in section 2.2.)102
+313.2 Q .996(After a connection is established,)127 329.4 R/F2 10
+/Times-Italic@0 SF(sendmail)3.496 E F1(mak)3.495 E .995(es the per)-.1 F .995
+(-mailer changes to the header and)-.2 F .236(sends the result to the mailer)
+102 341.4 R 5.236(.I)-.55 G 2.736(fa)228.406 341.4 S .537 -.15(ny m)238.912
+341.4 T .237(ail is rejected by the mailer).15 F 2.737(,a\215)-.4 G .237
+(ag is set to in)386.628 341.4 R -.2(vo)-.4 G .437 -.1(ke t).2 H .237
+(he return-).1 F(to-sender function after all deli)102 353.4 Q -.15(ve)-.25 G
+(ry completes.).15 E F0 2.5(3.6. Queued)87 377.4 R(Messages)2.5 E F1 .163
+(If the mailer returns a \231temporary f)127 393.6 R .163(ailure\232 e)-.1 F
+.162(xit status, the message is queued.)-.15 F 2.662(Ac)5.162 G .162
+(ontrol \214le is)455.336 393.6 R .85
+(used to describe the recipients to be sent to and v)102 405.6 R .851
+(arious other parameters.)-.25 F .851(This control \214le is for)5.851 F(-)-.2
+E 1.011(matted as a series of lines, each describing a sender)102 417.6 R 3.511
+(,ar)-.4 G 1.011(ecipient, the time of submission, or some)333.494 417.6 R .776
+(other salient parameter of the message.)102 429.6 R .776
+(The header of the message is stored in the control \214le, so)5.776 F(that th\
+e associated data \214le in the queue is just the temporary \214le that w)102
+441.6 Q(as originally collected.)-.1 E F0 2.5(3.7. Con\214guration)87 465.6 R
+F1 .493(Con\214guration is controlled primarily by a con\214guration \214le re\
+ad at startup.)127 481.8 R F2(Sendmail)5.492 E F1(should)2.992 E
+(not need to be recomplied e)102 493.8 Q(xcept)-.15 E 12.5(\(1\) T)107 510 R
+2.5(oc)-.8 G(hange operating systems \(V6, V7/32V)150.91 510 Q 2.5(,4)-1.29 G
+(BSD\).)313.21 510 Q 12.5(\(2\) T)107 526.2 R 2.5(or)-.8 G(emo)149.8 526.2 Q .3
+-.15(ve o)-.15 H 2.5(ri).15 G(nsert the DBM \(UNIX database\) library)192.27
+526.2 Q(.)-.65 E 12.5(\(3\) T)107 542.4 R 2.5(oc)-.8 G(hange ARP)150.91 542.4 Q
+(ANET reply codes.)-.92 E 12.5(\(4\) T)107 558.6 R 2.5(oa)-.8 G
+(dd headers \214elds requiring special processing.)150.91 558.6 Q .434
+(Adding mailers or changing parsing \(i.e., re)102 574.8 R .435
+(writing\) or routing information does not require recom-)-.25 F(pilation.)102
+586.8 Q 1.317(If the mail is being sent by a local user)127 603 R 3.817(,a)-.4
+G 1.317(nd the \214le \231.mailcf\232 e)303.914 603 R 1.317
+(xists in the sender')-.15 F 3.817(sh)-.55 G(ome)486.78 603 Q(directory)102 615
+Q 2.721(,t)-.65 G .221(hat \214le is read as a con\214guration \214le after th\
+e system con\214guration \214le.)145.451 615 R .222(The primary use)5.222 F
+(of this feature is to add header lines.)102 627 Q 3.25(The con\214guration \
+\214le encodes macro de\214nitions, header de\214nitions, mailer de\214nitions\
+,)127 643.2 R(re)102 655.2 Q(writing rules, and options.)-.25 E F0 2.5
+(3.7.1. Macr)102 679.2 R(os)-.18 E F1 .332(Macros can be used in three w)142
+695.4 R 2.833(ays. Certain)-.1 F .333(macros transmit unstructured te)2.833 F
+.333(xtual informa-)-.15 F .07(tion into the mail system, such as the name)117
+707.4 R F2(sendmail)2.57 E F1 .07
+(will use to identify itself in error messages.)2.57 F 1.247
+(Other macros transmit information from)117 719.4 R F2(sendmail)3.747 E F1
+1.247(to the con\214guration \214le for use in creating)3.747 F EP
+%%Page: 8 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 192.28(SMM:9-8 SENDMAIL)72 60 R 2.5<8a41>2.5 G 2.5(nI)
+383.99 60 S(nter)395.94 60 Q(netw)-.15 E(ork Mail Router)-.1 E/F1 10
+/Times-Roman@0 SF .312(other \214elds \(such as ar)117 96 R .312(gument v)-.18
+F .312(ectors to mailers\); e.g., the name of the sender)-.15 F 2.811(,a)-.4 G
+.311(nd the host and)442.237 96 R .848(user of the recipient.)117 108 R .848
+(Other macros are unused internally)5.848 F 3.348(,a)-.65 G .848
+(nd can be used as shorthand in the)361.142 108 R(con\214guration \214le.)117
+120 Q F0 2.5(3.7.2. Header)102 144 R(declarations)2.5 E F1 .355
+(Header declarations inform)142 160.2 R/F2 10/Times-Italic@0 SF(sendmail)2.854
+E F1 .354(of the format of kno)2.854 F .354(wn header lines.)-.25 F(Kno)5.354 E
+.354(wledge of)-.25 F 2.5(af)117 172.2 S .5 -.25(ew h)127.27 172.2 T
+(eader lines is b).25 E(uilt into)-.2 E F2(sendmail)2.5 E F1 2.5(,s)C
+(uch as the \231From:\232 and \231Date:\232 lines.)284.59 172.2 Q 1.201(Most c\
+on\214gured headers will be automatically inserted in the outgoing message if \
+the)142 188.4 R(y)-.15 E(don')117 200.4 Q 2.5(te)-.18 G
+(xist in the incoming message.)144.72 200.4 Q
+(Certain headers are suppressed by some mailers.)5 E F0 2.5(3.7.3. Mailer)102
+224.4 R(declarations)2.5 E F1 1.756(Mailer declarations tell)142 240.6 R F2
+(sendmail)4.256 E F1 1.756(of the v)4.256 F 1.756(arious mailers a)-.25 F -.25
+(va)-.2 G 1.756(ilable to it.).25 F 1.755(The de\214nition)6.755 F .119
+(speci\214es the internal name of the mailer)117 252.6 R 2.619(,t)-.4 G .12
+(he pathname of the program to call, some \215ags associ-)285.183 252.6 R 2.036
+(ated with the mailer)117 264.6 R 4.536(,a)-.4 G 2.036(nd an ar)213.894 264.6 R
+2.036(gument v)-.18 F 2.036(ector to be used on the call; this v)-.15 F 2.035
+(ector is macro-)-.15 F -.15(ex)117 276.6 S(panded before use.).15 E F0 2.5
+(3.7.4. Addr)102 300.6 R(ess r)-.18 E(ewriting rules)-.18 E F1 .458
+(The heart of address parsing in)142 316.8 R F2(sendmail)2.959 E F1 .459
+(is a set of re)2.959 F .459(writing rules.)-.25 F .459(These are an ordered)
+5.459 F .561(list of pattern-replacement rules, \(some)117 328.8 R .561
+(what lik)-.25 F 3.061(eap)-.1 G .561(roduction system, e)328.867 328.8 R .56
+(xcept that order is criti-)-.15 F 1.905
+(cal\), which are applied to each address.)117 340.8 R 1.905(The address is re)
+6.905 F 1.906(written te)-.25 F 1.906(xtually until it is either)-.15 F(re)117
+352.8 Q .308(written into a special canonical form \(i.e., a \(mailer)-.25 F
+2.807(,h)-.4 G .307(ost, user\) 3-tuple, such as {arpanet, usc-)342.118 352.8 R
+.64(isif, postel} representing the address \231postel@usc-isif\232\), or it f)
+117 364.8 R .641(alls of)-.1 F 3.141(ft)-.25 G .641(he end.)406.466 364.8 R
+.641(When a pattern)5.641 F(matches, the rule is reapplied until it f)117 376.8
+Q(ails.)-.1 E 1.222
+(The con\214guration \214le also supports the editing of addresses into dif)142
+393 R 1.221(ferent formats.)-.25 F -.15(Fo)6.221 G(r).15 E -.15(ex)117 405 S
+(ample, an address of the form:).15 E(ucsfcgl!tef)157 421.2 Q
+(might be mapped into:)117 437.4 Q(tef@ucsfcgl.UUCP)157 453.6 Q
+(to conform to the domain syntax.)117 469.8 Q -.35(Tr)5 G
+(anslations can also be done in the other direction.).35 E F0 2.5
+(3.7.5. Option)102 493.8 R(setting)2.5 E F1 1.168(There are se)142 510 R -.15
+(ve)-.25 G 1.169(ral options that can be set from the con\214guration \214le.)
+.15 F 1.169(These include the)6.169 F(pathnames of v)117 522 Q
+(arious support \214les, timeouts, def)-.25 E(ault modes, etc.)-.1 E F0 2.5
+(4. COMP)72 546 R(ARISON WITH O)-.74 E(THER MAILERS)-.4 E 2.5(4.1. Deli)87 570
+R -.1(ve)-.1 G(rmail).1 E F2(Sendmail)127 586.2 Q F1(is an outgro)2.5 E(wth of)
+-.25 E F2(delivermail)2.5 E F1 5(.T)C(he primary dif)301.18 586.2 Q
+(ferences are:)-.25 E 12.5(\(1\) Con\214guration)107 602.4 R .273
+(information is not compiled in.)2.773 F .272(This change simpli\214es man)
+5.273 F 2.772(yo)-.15 G 2.772(ft)445.686 602.4 S .272(he problems)454.568 602.4
+R(of mo)133.66 614.4 Q(ving to other machines.)-.15 E(It also allo)5 E
+(ws easy deb)-.25 E(ugging of ne)-.2 E 2.5(wm)-.25 G(ailers.)413.89 614.4 Q
+12.5(\(2\) Address)107 630.6 R .681(parsing is more \215e)3.181 F 3.182
+(xible. F)-.15 F .682(or e)-.15 F(xample,)-.15 E F2(delivermail)3.182 E F1 .682
+(only supported one g)3.182 F(ate)-.05 E -.1(wa)-.25 G 3.182(yt).1 G(o)499
+630.6 Q(an)133.66 642.6 Q 2.817(yn)-.15 G(etw)155.767 642.6 Q .317
+(ork, whereas)-.1 F F2(sendmail)2.817 E F1 .317(can be sensiti)2.817 F .616
+-.15(ve t)-.25 H 2.816(oh).15 G .316(ost names and reroute to dif)345.224 642.6
+R .316(ferent g)-.25 F(ate-)-.05 E -.1(wa)133.66 654.6 S(ys.).1 E 12.5(\(3\) F)
+107 670.8 R(orw)-.15 E 1.627(arding and :include: features eliminate the requi\
+rement that the system alias \214le be)-.1 F .074(writable by an)133.66 682.8 R
+2.574(yu)-.15 G .073
+(ser \(or that an update program be written, or that the system administration)
+203.442 682.8 R(mak)133.66 694.8 Q 2.5(ea)-.1 G(ll changes\).)162.16 694.8 Q
+(\(4\))107 711 Q F2(Sendmail)133.66 711 Q F1 .4
+(supports message batching across netw)2.9 F .401
+(orks when a message is being sent to mul-)-.1 F(tiple recipients.)133.66 723 Q
+EP
+%%Page: 9 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-9)462.9 60 Q/F1 10/Times-Roman@0 SF 12.5(\(5\) A)
+107 96 R .875(mail queue is pro)3.375 F .874(vided in)-.15 F/F2 10
+/Times-Italic@0 SF(sendmail.)3.374 E F1 .874(Mail that cannot be deli)5.874 F
+-.15(ve)-.25 G .874(red immediately b).15 F .874(ut can)-.2 F 1.063
+(potentially be deli)133.66 108 R -.15(ve)-.25 G 1.064
+(red later is stored in this queue for a later retry).15 F 6.064(.T)-.65 G
+1.064(he queue also pro-)427.218 108 R .896(vides a b)133.66 120 R(uf)-.2 E
+.896(fer ag)-.25 F .895
+(ainst system crashes; after the message has been collected it may be reli-)
+-.05 F(ably redeli)133.66 132 Q -.15(ve)-.25 G(red e).15 E -.15(ve)-.25 G 2.5
+(ni).15 G 2.5(ft)224.22 132 S(he system crashes during the initial deli)232.83
+132 Q -.15(ve)-.25 G(ry).15 E(.)-.65 E(\(6\))107 148.2 Q F2(Sendmail)133.66
+148.2 Q F1 .197(uses the netw)2.696 F .197(orking support pro)-.1 F .197
+(vided by 4.2BSD to pro)-.15 F .197(vide a direct interf)-.15 F .197(ace net-)
+-.1 F -.1(wo)133.66 160.2 S .07(rks such as the ARP).1 F .07
+(ANET and/or Ethernet using SMTP \(the Simple Mail T)-.92 F .07(ransfer Proto-)
+-.35 F(col\) o)133.66 172.2 Q -.15(ve)-.15 G 2.5(raT).15 G(CP/IP connection.)
+184.73 172.2 Q F0 2.5(4.2. MMDF)87 196.2 R F1 .957(MMDF [Crock)127 212.4 R .957
+(er79] spans a wider problem set than)-.1 F F2(sendmail)3.458 E F1 5.958(.F)C
+.958(or e)395.058 212.4 R .958(xample, the domain of)-.15 F .721
+(MMDF includes a \231phone netw)102 224.4 R .721(ork\232 mailer)-.1 F 3.221(,w)
+-.4 G(hereas)290.516 224.4 Q F2(sendmail)3.221 E F1 .721(calls on pree)3.221 F
+.72(xisting mailers in most)-.15 F(cases.)102 236.4 Q .175(MMDF and)127 252.6 R
+F2(sendmail)2.675 E F1 .175
+(both support aliasing, customized mailers, message batching, automatic)2.675 F
+(forw)102 264.6 Q .792(arding to g)-.1 F(ate)-.05 E -.1(wa)-.25 G .792
+(ys, queueing, and retransmission.).1 F .792(MMDF supports tw)5.792 F .792
+(o-stage timeout, which)-.1 F F2(sendmail)102 276.6 Q F1(does not support.)2.5
+E(The con\214guration for MMDF is compiled into the code)127 294.8 Q/F3 7
+/Times-Roman@0 SF(4)348.65 290.8 Q F1(.)352.15 294.8 Q .037
+(Since MMDF does not consider backw)127 311 R .037
+(ards compatibility as a design goal, the address parsing)-.1 F(is simpler b)
+102 323 Q(ut much less \215e)-.2 E(xible.)-.15 E 1.159(It is some)127 341.2 R
+1.159(what harder to inte)-.25 F 1.159(grate a ne)-.15 F 3.659(wc)-.25 G
+(hannel)302.802 341.2 Q F3(5)329.462 337.2 Q F1 1.159(into MMDF)336.621 341.2 R
+6.16(.I)-.8 G 3.66(np)397.59 341.2 S(articular)411.25 341.2 Q 3.66(,M)-.4 G
+1.16(MDF must)459.22 341.2 R(kno)102 353.2 Q 3.225(wt)-.25 G .725(he location \
+and format of host tables for all channels, and the channel must speak a speci\
+al)129.975 353.2 R 2.525(protocol. This)102 365.2 R(allo)2.525 E .025
+(ws MMDF to do additional v)-.25 F .025(eri\214cation \(such as v)-.15 F .025
+(erifying host names\) at submis-)-.15 F(sion time.)102 377.2 Q 1.761
+(MMDF strictly separates the submission and deli)127 393.4 R -.15(ve)-.25 G
+1.761(ry phases.).15 F(Although)6.761 E F2(sendmail)4.261 E F1 1.76(has the)
+4.261 F .784(concept of each of these stages, the)102 405.4 R 3.284(ya)-.15 G
+.784(re inte)260.068 405.4 R .785(grated into one program, whereas in MMDF the)
+-.15 F 3.285(ya)-.15 G(re)496.23 405.4 Q(split into tw)102 417.4 Q 2.5(op)-.1 G
+(rograms.)162.19 417.4 Q F0 2.5(4.3. Message)87 441.4 R(Pr)2.5 E
+(ocessing Module)-.18 E F1 .925
+(The Message Processing Module \(MPM\) discussed by Postel [Postel79b] matches)
+127 457.6 R F2(sendmail)3.425 E F1 1.364
+(closely in terms of its basic architecture.)102 469.6 R(Ho)6.364 E(we)-.25 E
+-.15(ve)-.25 G 2.164 -.4(r, l).15 H(ik).4 E 3.864(eM)-.1 G(MDF)347.526 469.6 Q
+3.864(,t)-.8 G 1.365(he MPM includes the netw)377.54 469.6 R(ork)-.1 E(interf)
+102 481.6 Q(ace softw)-.1 E(are as part of its domain.)-.1 E .408
+(MPM also postulates a duple)127 497.8 R 2.907(xc)-.15 G .407
+(hannel to the recei)256.937 497.8 R -.15(ve)-.25 G 1.207 -.4(r, a).15 H 2.907
+(sd).4 G .407(oes MMDF)365.362 497.8 R 2.907(,t)-.8 G .407(hus allo)419.546
+497.8 R .407(wing simpler)-.25 F .302
+(handling of errors by the mailer than is possible in)102 509.8 R F2(sendmail)
+2.802 E F1 5.302(.W)C .302(hen a message queued by)362.24 509.8 R F2(sendmail)
+2.802 E F1 .23(is sent, an)102 521.8 R 2.73(ye)-.15 G .23
+(rrors must be returned to the sender by the mailer itself.)154.2 521.8 R .229
+(Both MPM and MMDF mail-)5.229 F .883(ers can return an immediate error respon\
+se, and a single error processor can create an appropriate)102 533.8 R
+(response.)102 545.8 Q 2.24
+(MPM prefers passing the message as a structured object, with type-length-v)127
+564 R 2.24(alue tuples)-.25 F F3(6)498 560 Q F1(.)501.5 564 Q .874(Such a con)
+102 576 R -.15(ve)-.4 G .874(ntion requires a much higher de).15 F .875
+(gree of cooperation between mailers than is required)-.15 F(by)102 588 Q F2
+(sendmail)2.796 E F1 5.296(.M)C .296(PM also assumes a uni)167.592 588 R -.15
+(ve)-.25 G .296(rsally agreed upon internet name space \(with each address).15
+F(in the form of a net-host-user tuple\), which)102 600 Q F2(sendmail)2.5 E F1
+(does not.)2.5 E .32 LW 76 642 72 642 DL 80 642 76 642 DL 84 642 80 642 DL 88
+642 84 642 DL 92 642 88 642 DL 96 642 92 642 DL 100 642 96 642 DL 104 642 100
+642 DL 108 642 104 642 DL 112 642 108 642 DL 116 642 112 642 DL 120 642 116 642
+DL 124 642 120 642 DL 128 642 124 642 DL 132 642 128 642 DL 136 642 132 642 DL
+140 642 136 642 DL 144 642 140 642 DL 148 642 144 642 DL 152 642 148 642 DL 156
+642 152 642 DL 160 642 156 642 DL 164 642 160 642 DL 168 642 164 642 DL 172 642
+168 642 DL 176 642 172 642 DL 180 642 176 642 DL 184 642 180 642 DL 188 642 184
+642 DL 192 642 188 642 DL 196 642 192 642 DL 200 642 196 642 DL 204 642 200 642
+DL 208 642 204 642 DL 212 642 208 642 DL 216 642 212 642 DL/F4 5/Times-Roman@0
+SF(4)93.6 652.4 Q/F5 8/Times-Roman@0 SF .179
+(Dynamic con\214guration tables are currently being considered for MMDF; allo)
+3.2 J .18(wing the installer to select either compiled or dy-)-.2 F
+(namic tables.)72 665.2 Q F4(5)93.6 675.6 Q F5(The MMDF equi)3.2 I -.2(va)-.2 G
+(lent of a).2 E/F6 8/Times-Italic@0 SF(sendmail)2 E F5(\231mailer)2 E -.56
+<2e9a>-.44 G F4(6)93.6 689.2 Q F5(This is similar to the NBS standard.)3.2 I EP
+%%Page: 10 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 187.28(SMM:9-10 SENDMAIL)72 60 R 2.5<8a41>2.5 G 2.5(nI)
+383.99 60 S(nter)395.94 60 Q(netw)-.15 E(ork Mail Router)-.1 E 2.5(5. EV)72 96
+R(ALU)-1.35 E -.95(AT)-.6 G(IONS AND FUTURE PLANS).95 E/F1 10/Times-Italic@0 SF
+(Sendmail)112 112.2 Q/F2 10/Times-Roman@0 SF 1.851(is designed to w)4.351 F
+1.851(ork in a nonhomogeneous en)-.1 F 4.352(vironment. Ev)-.4 F 1.852
+(ery attempt is made to)-.15 F -.2(avo)87 124.2 S 1.037
+(id imposing unnecessary constraints on the underlying mailers.).2 F 1.036
+(This goal has dri)6.036 F -.15(ve)-.25 G 3.536(nm).15 G 1.036(uch of the)
+461.938 124.2 R 2.723(design. One)87 136.2 R .223(of the major problems has be\
+en the lack of a uniform address space, as postulated in [Pos-)2.723 F
+(tel79a] and [Postel79b].)87 148.2 Q 2.647(An)112 164.4 S .147(onuniform addre\
+ss space implies that a path will be speci\214ed in all addresses, either e)
+126.867 164.4 R(xplicitly)-.15 E .472
+(\(as part of the address\) or implicitly \(as with implied forw)87 176.4 R
+.473(arding to g)-.1 F(ate)-.05 E -.1(wa)-.25 G 2.973(ys\). This).1 F .473
+(restriction has the)2.973 F .493(unpleasant ef)87 188.4 R .493
+(fect of making replying to messages e)-.25 F .493(xceedingly dif)-.15 F .493
+(\214cult, since there is no one \231address\232)-.25 F(for an)87 200.4 Q 2.5
+(yp)-.15 G(erson, b)122.95 200.4 Q(ut only a w)-.2 E
+(ay to get there from where)-.1 E -.15(ve)-.25 G 2.5(ry).15 G(ou are.)324.7
+200.4 Q(Interf)112 216.6 Q .448(acing to mail programs that were not initially\
+ intended to be applied in an internet en)-.1 F(viron-)-.4 E(ment has been ama\
+zingly successful, and has reduced the job to a manageable task.)87 228.6 Q F1
+(Sendmail)112 244.8 Q F2 2.906(has kno)5.406 F 2.906(wledge of a fe)-.25 F
+5.406(wd)-.25 G(if)271.126 244.8 Q 2.906(\214cult en)-.25 F 2.906(vironments b)
+-.4 F 2.906(uilt in.)-.2 F 2.905(It generates ARP)7.906 F(ANET)-.92 E .648(FTP\
+/SMTP compatible error messages \(prepended with three-digit numbers [Neigus73\
+, Postel74, Pos-)87 256.8 R .771(tel82]\) as necessary)87 268.8 R 3.271(,o)-.65
+G .771(ptionally generates UNIX-style \231From\232 lines on the front of messa\
+ges for some)177.523 268.8 R 1.669(mailers, and kno)87 280.8 R 1.669(ws ho)-.25
+F 4.169(wt)-.25 G 4.169(op)195.666 280.8 S 1.669(arse the same lines on input.)
+209.835 280.8 R 1.67(Also, error handling has an option cus-)6.67 F
+(tomized for BerkNet.)87 292.8 Q 1.482(The decision to a)112 309 R -.2(vo)-.2 G
+1.482(id doing an).2 F 3.982(yt)-.15 G 1.481(ype of deli)254.222 309 R -.15(ve)
+-.25 G 1.481(ry where possible \(e).15 F -.15(ve)-.25 G 1.481
+(n, or perhaps especially).15 F(,)-.65 E .574(local deli)87 321 R -.15(ve)-.25
+G .574(ry\) has turned out to be a good idea.).15 F(Ev)5.574 E .574
+(en with local deli)-.15 F -.15(ve)-.25 G(ry).15 E 3.074(,t)-.65 G .575
+(here are issues of the loca-)394.776 321 R .469(tion of the mailbox, the form\
+at of the mailbox, the locking protocol used, etc., that are best decided by)87
+333 R .038(other programs.)87 345 R .038(One surprisingly major anno)5.038 F
+.038(yance in man)-.1 F 2.538(yi)-.15 G .038
+(nternet mailers is that the location and for)333.684 345 R(-)-.2 E .138
+(mat of local mail is b)87 357 R .138(uilt in.)-.2 F .137
+(The feeling seems to be that local mail is so common that it should be ef)
+5.137 F<8c2d>-.25 E 3.045(cient. This)87 369 R .545
+(feeling is not born out by our e)3.045 F .545(xperience; on the contrary)-.15
+F 3.045(,t)-.65 G .545(he location and format of mail-)376.575 369 R(box)87 381
+Q(es seems to v)-.15 E(ary widely from system to system.)-.25 E .681
+(The ability to automatically generate a response to incoming mail \(by forw)
+112 397.2 R .68(arding mail to a pro-)-.1 F .435
+(gram\) seems useful \(\231I am on v)87 409.2 R .435
+(acation until late August....)-.25 F 2.935(\232\) b)-.7 F .435
+(ut can create problems such as forw)-.2 F(ard-)-.1 E .143(ing loops \(tw)87
+421.2 R 2.643(op)-.1 G .143(eople on v)152.609 421.2 R .143(acation whose prog\
+rams send notes back and forth, for instance\) if these pro-)-.25 F .732
+(grams are not well written.)87 433.2 R 3.232(Ap)5.732 G .732
+(rogram could be written to do standard tasks correctly)218.592 433.2 R 3.233
+(,b)-.65 G .733(ut this w)450.404 433.2 R(ould)-.1 E(solv)87 445.2 Q 2.5(et)
+-.15 G(he general case.)113.24 445.2 Q .225
+(It might be desirable to implement some form of load limiting.)112 461.4 R
+2.725(Ia)5.225 G 2.724(mu)380.8 461.4 S(na)396.304 461.4 Q -.1(wa)-.15 G .224
+(re of an).1 F 2.724(ym)-.15 G .224(ail system)463.496 461.4 R
+(that addresses this problem, nor am I a)87 473.4 Q -.1(wa)-.15 G(re of an).1 E
+2.5(yr)-.15 G(easonable solution at this time.)294.05 473.4 Q .113(The con\214\
+guration \214le is currently practically inscrutable; considerable con)112
+489.6 R -.15(ve)-.4 G .114(nience could be real-).15 F(ized with a higher)87
+501.6 Q(-le)-.2 E -.15(ve)-.25 G 2.5(lf).15 G(ormat.)186.93 501.6 Q .778(It se\
+ems clear that common protocols will be changing soon to accommodate changing \
+require-)112 517.8 R 2.774(ments and en)87 529.8 R 5.274(vironments. These)-.4
+F 2.774(changes will include modi\214cations to the message header \(e.g.,)
+5.274 F .859([NBS80]\) or to the body of the message itself \(such as for mult\
+imedia messages [Postel80]\).)87 541.8 R(Experi-)5.859 E
+(ence indicates that these changes should be relati)87 553.8 Q -.15(ve)-.25 G
+(ly tri).15 E(vial to inte)-.25 E(grate into the e)-.15 E(xisting system.)-.15
+E .811(In tightly coupled en)112 570 R .812(vironments, it w)-.4 F .812
+(ould be nice to ha)-.1 F 1.112 -.15(ve a n)-.2 H .812(ame serv).15 F .812
+(er such as Grapvine [Bir)-.15 F(-)-.2 E .095(rell82] inte)87 582 R .095
+(grated into the mail system.)-.15 F .095(This w)5.095 F .095(ould allo)-.1 F
+2.594(was)-.25 G .094(ite such as \231Berk)330.768 582 R(ele)-.1 E .094
+(y\232 to appear as a single)-.15 F 2.606
+(host, rather than as a collection of hosts, and w)87 594 R 2.606(ould allo)-.1
+F 5.106(wp)-.25 G 2.606(eople to mo)352.786 594 R 2.906 -.15(ve t)-.15 H 2.606
+(ransparently among).15 F 1.664(machines without ha)87 606 R 1.664
+(ving to change their addresses.)-.2 F 1.664(Such a f)6.664 F 1.664(acility w)
+-.1 F 1.663(ould require an automatically)-.1 F .428
+(updated database and some method of resolving con\215icts.)87 618 R .428
+(Ideally this w)5.428 F .428(ould be ef)-.1 F(fecti)-.25 E .728 -.15(ve e)-.25
+H -.15(ve)-.1 G 2.928(nw).15 G(ithout)480.66 618 Q .184
+(all hosts being under a single management.)87 630 R(Ho)5.184 E(we)-.25 E -.15
+(ve)-.25 G .984 -.4(r, i).15 H 2.684(ti).4 G 2.683(sn)317.576 630 S .183
+(ot clear whether this feature should be inte-)329.149 630 R
+(grated into the aliasing f)87 642 Q(acility or should be considered a \231v)
+-.1 E(alue added\232 feature outside)-.25 E F1(sendmail)2.5 E F2(itself.)2.5 E
+.79(As a more interesting case, the CSNET name serv)112 658.2 R .791
+(er [Solomon81] pro)-.15 F .791(vides an f)-.15 F .791(acility that goes)-.1 F
+(be)87 670.2 Q .375(yond a single tightly-coupled en)-.15 F 2.875
+(vironment. Such)-.4 F 2.875(af)2.875 G .375(acility w)308.675 670.2 R .374
+(ould normally e)-.1 F .374(xist outside of)-.15 F F1(sendmail)2.874 E F2(ho)87
+682.2 Q(we)-.25 E -.15(ve)-.25 G -.55(r.).15 G EP
+%%Page: 11 11
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-11)457.9 60 Q -.55(AC)72 96 S(KNO).55 E
+(WLEDGEMENTS)-.5 E/F1 10/Times-Roman@0 SF 1.203(Thanks are due to K)97 112.2 R
+1.204
+(urt Shoens for his continual cheerful assistance and good advice, Bill Jo)-.15
+F 3.704(yf)-.1 G(or)495.67 112.2 Q .102
+(pointing me in the correct direction \(o)72 124.2 R -.15(ve)-.15 G 2.602(ra)
+.15 G .102(nd o)244.324 124.2 R -.15(ve)-.15 G .102
+(r\), and Mark Horton for more advice, prodding, and man).15 F(y)-.15 E .453
+(of the good ideas.)72 136.2 R -.15(Ku)5.453 G .453
+(rt and Eric Schmidt are to be credited for using).15 F/F2 10/Times-Italic@0 SF
+(delivermail)2.953 E F1 .453(as a serv)2.953 F .453(er for their pro-)-.15 F
+1.663(grams \()72 148.2 R F2(Mail)A F1 1.663(and BerkNet respecti)4.163 F -.15
+(ve)-.25 G 1.663(ly\) before an).15 F 4.163(ys)-.15 G 1.663
+(ane person should ha)291.091 148.2 R -.15(ve)-.2 G 4.163(,a).15 G 1.662
+(nd making the necessary)400.423 148.2 R .078
+(modi\214cations promptly and happily)72 160.2 R 5.078(.E)-.65 G .078(ric g)
+228.332 160.2 R -2.25 -.2(av e)-.05 H .079
+(me considerable advice about the perils of netw)2.778 F .079(ork softw)-.1 F
+(are)-.1 E .179(which sa)72 172.2 R -.15(ve)-.2 G 2.679(dm).15 G 2.679(ea)
+131.998 172.2 S 2.679(nu)143.557 172.2 S(nkno)156.236 172.2 Q .178
+(wn amount of w)-.25 F .178(ork and grief.)-.1 F .178
+(Mark did the original implementation of the DBM)5.178 F -.15(ve)72 184.2 S
+.341(rsion of aliasing, installed the VFORK code, wrote the current v).15 F
+.341(ersion of)-.15 F F2(rmail)2.841 E F1 2.841(,a)C .341(nd w)411.083 184.2 R
+.342(as the person who)-.1 F .61(really con)72 196.2 R .61
+(vinced me to put the w)-.4 F .61(ork into)-.1 F F2(delivermail)3.109 E F1 .609
+(to turn it into)3.109 F F2(sendmail)3.109 E F1 5.609(.K)C .609(urt deserv)
+398.753 196.2 R .609(es accolades for)-.15 F(using)72 208.2 Q F2(sendmail)2.57
+E F1 .07(when I w)2.57 F .07(as myself afraid to tak)-.1 F 2.57(et)-.1 G .07
+(he risk; ho)271.01 208.2 R 2.57(wap)-.25 G .07
+(erson can continue to be so enthusiastic in)334.92 208.2 R(the f)72 220.2 Q
+(ace of so much bitter reality is be)-.1 E(yond me.)-.15 E -.15(Ku)97 236.4 S
+1.505(rt, Mark, Kirk McK).15 F 1.505(usick, Marvin Solomon, and man)-.15 F
+4.005(yo)-.15 G 1.504(thers ha)345.79 236.4 R 1.804 -.15(ve r)-.2 H -.25(ev).15
+G(ie).25 E 1.504(wed this paper)-.25 F 4.004(,g)-.4 G -.25(iv)483.69 236.4 S
+(ing).25 E(considerable useful advice.)72 248.4 Q .846
+(Special thanks are reserv)97 264.6 R .846(ed for Mik)-.15 F 3.346(eS)-.1 G
+(tonebrak)256.786 264.6 Q .846(er at Berk)-.1 F(ele)-.1 E 3.347(ya)-.15 G .847
+(nd Bob Epstein at Britton-Lee, who)356.995 264.6 R .542(both kno)72 276.6 R
+.542(wingly allo)-.25 F .542(wed me to put so much w)-.25 F .541
+(ork into this project when there were so man)-.1 F 3.041(yo)-.15 G .541
+(ther things I)454.588 276.6 R(really should ha)72 288.6 Q .3 -.15(ve b)-.2 H
+(een w).15 E(orking on.)-.1 E EP
+%%Page: 12 12
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF(REFERENCES)256.605 132 Q 62.73([Birrell82] Birrell,)72
+148.2 R 1.084(A. D., Le)3.584 F 1.084(vin, R., Needham, R. M., and Schroeder)
+-.25 F 3.584(,M)-.4 G 3.585(.D)433.49 148.2 S 1.085(., \231Grape)446.795 148.2
+R(vine:)-.25 E(An Ex)180 160.2 Q(ercise in Distrib)-.15 E(uted Computing.)-.2 E
+5<9a49>-.7 G(n)348.66 160.2 Q/F1 10/Times-Italic@0 SF(Comm. A.C.M. 25,)2.5 E F0
+(4, April 82.)2.5 E 59.4([Borden79] Borden,)72 176.4 R .796
+(S., Gaines, R. S., and Shapiro, N. Z.,)3.296 F F1 .795(The MH Messa)3.295 F
+.995 -.1(ge H)-.1 H .795(andling Sys-).1 F(tem: User)180 188.4 Q(s' Manual.)-.1
+E F0(R-2367-P)5 E(AF)-.92 E 5(.R)-.8 G(and Corporation.)332.06 188.4 Q
+(October 1979.)5 E([Crock)72 204.6 Q 52.29(er77a] Crock)-.1 F(er)-.1 E 2.508
+(,D)-.4 G 2.508(.H)223.938 204.6 S .008(., V)236.166 204.6 R .009
+(ittal, J. J., Pogran, K. T)-.6 F .009(., and Henderson, D. A. Jr)-.74 F(.,)
+-.55 E F1(Standar)2.509 E 2.509(df)-.37 G(or)495.11 204.6 Q .955(the F)180
+216.6 R .955(ormat of ARP)-1.05 F 3.454(AN)-.9 G .954(etwork T)272.978 216.6 R
+-.2(ex)-.92 G 3.454(tM).2 G(essa)331.536 216.6 Q -.1(ge)-.1 G(s.).1 E F0 .954
+(RFC 733, NIC 41952.)5.954 F .954(In [Fein-)5.954 F 2.5(ler78]. No)180 228.6 R
+-.15(ve)-.15 G(mber 1977.).15 E([Crock)72 244.8 Q 51.73(er77b] Crock)-.1 F(er)
+-.1 E 3.04(,D)-.4 G 3.04(.H)224.47 244.8 S(.,)237.23 244.8 Q F1 -1.55 -.55
+(Fr a)3.04 H(me).55 E .54(work and Functions of the MS P)-.15 F(er)-.8 E .54
+(sonal Messa)-.1 F .74 -.1(ge S)-.1 H(ystem.).1 E F0(R-2134-ARP)180 256.8 Q
+(A, Rand Corporation, Santa Monica, California.)-.92 E(1977.)5 E([Crock)72 273
+Q 56.73(er79] Crock)-.1 F(er)-.1 E 2.557(,D)-.4 G 2.557(.H)223.987 273 S .056
+(., Szurk)236.264 273 R -.25(ow)-.1 G .056(ski, E. S., and F).25 F(arber)-.15 E
+2.556(,D)-.4 G 2.556(.J)374.85 273 S(.,)383.796 273 Q F1 .056
+(An Internetwork Memo Dis-)2.556 F(trib)180 285 Q 1.341(ution F)-.2 F 1.341
+(acility \212 MMDF)-.75 F(.)-1.35 E F0 1.341
+(6th Data Communication Symposium, Asilomar)6.341 F(.)-.55 E(No)180 297 Q -.15
+(ve)-.15 G(mber 1979.).15 E([Crock)72 313.2 Q 56.73(er82] Crock)-.1 F(er)-.1 E
+3.383(,D)-.4 G 3.383(.H)224.813 313.2 S(.,)237.916 313.2 Q F1(Standar)3.383 E
+3.383(df)-.37 G .883(or the F)288.762 313.2 R .882(ormat of Arpa Internet T)
+-1.05 F -.2(ex)-.92 G 3.382(tM).2 G(essa)446.368 313.2 Q -.1(ge)-.1 G(s.).1 E
+F0(RFC)5.882 E 4.197(822. Netw)180 325.2 R 1.697(ork Information Center)-.1 F
+4.197(,S)-.4 G 1.698(RI International, Menlo P)333.768 325.2 R 1.698
+(ark, California.)-.15 F(August 1982.)180 337.2 Q 53.3([Metcalfe76] Metcalfe,)
+72 353.4 R .727(R., and Boggs, D., \231Ethernet: Distrib)3.227 F .727(uted P)
+-.2 F(ack)-.15 E .727(et Switching for Local)-.1 F(Computer Netw)180 365.4 Q
+(orks\232,)-.1 E F1(Communications of the A)2.5 E(CM 19,)-.3 E F0 2.5(7. July)
+2.5 F(1976.)2.5 E 60.51([Feinler78] Feinler)72 381.6 R 4.438(,E)-.4 G 1.938
+(., and Postel, J.)220.978 381.6 R(\(eds.\),)6.938 E F1(ARP)4.438 E 1.938
+(ANET Pr)-.9 F 1.938(otocol Handbook.)-.45 F F0 1.938(NIC 7104,)6.938 F(Netw)
+180 393.6 Q(ork Information Center)-.1 E 2.5(,S)-.4 G
+(RI International, Menlo P)304.48 393.6 Q(ark, California.)-.15 E(1978.)5 E
+69.39([NBS80] National)72 409.8 R 1.46(Bureau of Standards,)3.96 F F1 1.46
+(Speci\214cation of a Dr)3.96 F 1.46(aft Messa)-.15 F 1.66 -.1(ge F)-.1 H 1.46
+(ormat Stan-)-.95 F(dar)180 421.8 Q(d.)-.37 E F0(Report No. ICST/CBOS 80-2.)5 E
+(October 1980.)5 E 60.51([Neigus73] Neigus,)72 438 R(N.,)5.186 E F1 -.45(Fi)
+5.186 G 2.686(le T).45 F -.15(ra)-.55 G 2.686(nsfer Pr).15 F 2.686
+(otocol for the ARP)-.45 F 5.187(AN)-.9 G(etwork.)402.599 438 Q F0 2.687
+(RFC 542, NIC)7.687 F 2.5(17759. In)180 450 R 2.5([Feinler78]. August,)2.5 F
+(1973.)2.5 E([No)72 466.2 Q 55.21(witz78a] No)-.25 F 1.633
+(witz, D. A., and Lesk, M. E.,)-.25 F F1 4.132(AD)4.132 G 1.632
+(ial-Up Network of UNIX Systems.)338.9 466.2 R F0(Bell)6.632 E 5.403
+(Laboratories. In)180 478.2 R 2.904(UNIX Programmer')5.403 F 5.404(sM)-.55 G
+2.904(anual, Se)356.024 478.2 R -.15(ve)-.25 G 2.904(nth Edition, V).15 F 2.904
+(olume 2.)-1.29 F(August, 1978.)180 490.2 Q([No)72 506.4 Q 54.65(witz78b] No)
+-.25 F .633(witz, D. A.,)-.25 F F1 .632(Uucp Implementation Description.)3.132
+F F0 .632(Bell Laboratories.)5.632 F .632(In UNIX)5.632 F(Programmer')180 518.4
+Q 2.5(sM)-.55 G(anual, Se)248.05 518.4 Q -.15(ve)-.25 G(nth Edition, V).15 E
+(olume 2.)-1.29 E(October)5 E 2.5(,1)-.4 G(978.)431.22 518.4 Q 64.39
+([Postel74] Postel,)72 534.6 R .24(J., and Neigus, N., Re)2.74 F .241
+(vised FTP Reply Codes.)-.25 F .241(RFC 640, NIC 30843.)5.241 F(In)5.241 E 2.5
+([Feinler78]. June,)180 546.6 R(1974.)2.5 E 64.39([Postel77] Postel,)72 562.8 R
+(J.,)2.5 E F1(Mail Pr)2.5 E(otocol.)-.45 E F0(NIC 29588.)5 E(In [Feinler78].)5
+E(No)5 E -.15(ve)-.15 G(mber 1977.).15 E 59.95([Postel79a] Postel,)72 579 R
+(J.,)3.144 E F1 .644(Internet Messa)3.144 F .844 -.1(ge P)-.1 H -.45(ro).1 G
+(tocol.).45 E F0 .644(RFC 753, IEN 85.)5.644 F(Netw)5.644 E .644
+(ork Information)-.1 F(Center)180 591 Q 2.5(,S)-.4 G(RI International, Menlo P)
+216.82 591 Q(ark, California.)-.15 E(March 1979.)5 E 59.39([Postel79b] Postel,)
+72 607.2 R 1.305(J. B.,)3.805 F F1 1.305(An Internetwork Messa)3.805 F 1.505
+-.1(ge S)-.1 H(tructur).1 E -.15(e.)-.37 G F0(In)6.456 E F1(Pr)3.806 E 1.306
+(oceedings of the Sixth)-.45 F(Data Communications Symposium,)180 619.2 Q F0
+2.5(IEEE. Ne)2.5 F 2.5(wY)-.25 G 2.5(ork. No)379.74 619.2 R -.15(ve)-.15 G
+(mber 1979.).15 E 64.39([Postel80] Postel,)72 635.4 R .639(J. B.,)3.139 F F1
+3.139(AS)3.139 G(tructur)248.676 635.4 Q .639(ed F)-.37 F .639(ormat for T)
+-1.05 F -.15(ra)-.55 G .639(nsmission of Multi-Media Documents.).15 F F0 .418
+(RFC 767.)180 647.4 R(Netw)5.419 E .419(ork Information Center)-.1 F 2.919(,S)
+-.4 G .419(RI International, Menlo P)350.474 647.4 R .419(ark, Califor)-.15 F
+(-)-.2 E 2.5(nia. August)180 659.4 R(1980.)2.5 E 64.39([Postel82] Postel,)72
+675.6 R 2.05(J. B.,)4.55 F F1 2.05(Simple Mail T)4.55 F -.15(ra)-.55 G 2.05
+(nsfer Pr).15 F(otocol.)-.45 E F0 2.05(RFC821 \(obsoleting RFC788\).)7.05 F
+(Netw)180 687.6 Q .273(ork Information Center)-.1 F 2.774(,S)-.4 G .274
+(RI International, Menlo P)305.3 687.6 R .274(ark, California.)-.15 F(August)
+5.274 E(1982.)180 699.6 Q/F2 10/Times-Bold@0 SF 187.28(SMM:9-12 SENDMAIL)72 756
+R 2.5<8a41>2.5 G 2.5(nI)383.99 756 S(nter)395.94 756 Q(netw)-.15 E
+(ork Mail Router)-.1 E EP
+%%Page: 13 13
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(SENDMAIL \212 An Inter)72 60 Q(netw)-.15 E
+(ork Mail Router)-.1 E(SMM:9-13)457.9 60 Q/F1 10/Times-Roman@0 SF 55.5
+([Schmidt79] Schmidt,)72 96 R(E.,)2.972 E/F2 10/Times-Italic@0 SF .472(An Intr)
+2.972 F .472(oduction to the Berk)-.45 F(ele)-.1 E 2.972(yN)-.3 G(etwork.)
+369.664 96 Q F1(Uni)5.472 E -.15(ve)-.25 G .472(rsity of California,).15 F
+(Berk)180 108 Q(ele)-.1 E 2.5(yC)-.15 G 2.5(alifornia. 1979.)225.02 108 R 59.95
+([Shoens79] Shoens,)72 124.2 R(K.,)4.894 E F2 2.394(Mail Refer)4.894 F 2.394
+(ence Manual.)-.37 F F1(Uni)7.394 E -.15(ve)-.25 G 2.395
+(rsity of California, Berk).15 F(ele)-.1 E 6.195 -.65(y. I)-.15 H(n).65 E
+(UNIX Programmer')180 136.2 Q 2.5(sM)-.55 G(anual, Se)275.54 136.2 Q -.15(ve)
+-.25 G(nth Edition, V).15 E(olume 2C.)-1.29 E(December 1979.)5 E 60.51
+([Sluizer81] Sluizer)72 152.4 R 2.872(,S)-.4 G .372(., and Postel, J. B.,)
+218.862 152.4 R F2 .372(Mail T)2.872 F -.15(ra)-.55 G .372(nsfer Pr).15 F
+(otocol.)-.45 E F1 .371(RFC 780.)5.371 F(Netw)5.371 E .371(ork Infor)-.1 F(-)
+-.2 E(mation Center)180 164.4 Q 2.5(,S)-.4 G(RI International, Menlo P)247.1
+164.4 Q(ark, California.)-.15 E(May 1981.)5 E 52.72([Solomon81] Solomon,)72
+180.6 R .96(M., Landweber)3.46 F 3.46(,L)-.4 G .96
+(., and Neuhengen, D., \231The Design of the CSNET)296.08 180.6 R(Name Serv)180
+192.6 Q(er)-.15 E 3.9 -.7(.\232 C)-.55 H(S-DN-2, Uni).7 E -.15(ve)-.25 G
+(rsity of W).15 E(isconsin, Madison.)-.4 E(No)5 E -.15(ve)-.15 G(mber 1981.).15
+E 78.28([Su82] Su,)72 208.8 R(Za)4.344 E 1.844(w-Sing, and Postel, Jon,)-.15 F
+F2 1.844(The Domain Naming Con)4.344 F 1.844(vention for Internet)-.4 F 1.717
+(User Applications.)180 220.8 R F1 4.217(RFC819. Netw)6.717 F 1.717
+(ork Information Center)-.1 F 4.217(,S)-.4 G 1.718(RI International,)436.182
+220.8 R(Menlo P)180 232.8 Q(ark, California.)-.15 E(August 1982.)5 E([UNIX83])
+72 249 Q F2 2.12(The UNIX Pr)180 249 R -.1(og)-.45 G -.15(ra).1 G(mmer').15 E
+4.62(sM)-.4 G 2.12(anual, Se)298.3 249 R 2.12(venth Edition,)-.15 F F1 -.6(Vi)
+4.62 G 2.12(rtual V).6 F 2.12(AX-11 V)-1.35 F(ersion,)-1.11 E -1.29(Vo)180 261
+S 1.027(lume 1.)1.29 F 1.027(Bell Laboratories, modi\214ed by the Uni)6.027 F
+-.15(ve)-.25 G 1.027(rsity of California, Berk).15 F(e-)-.1 E(le)180 273 Q 1.3
+-.65(y, C)-.15 H 2.5(alifornia. March,).65 F(1983.)2.5 E EP
+%%Trailer
+end
+%%EOF
diff --git a/usr.sbin/sendmail/doc/op/Makefile b/usr.sbin/sendmail/doc/op/Makefile
new file mode 100644
index 0000000..e8f791a
--- /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 0000000..9678d14
--- /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/op/op.ps b/usr.sbin/sendmail/doc/op/op.ps
new file mode 100644
index 0000000..d0abd0c
--- /dev/null
+++ b/usr.sbin/sendmail/doc/op/op.ps
@@ -0,0 +1,5477 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Bold
+%%+ font Times-Roman
+%%+ font Times-Italic
+%%+ font Symbol
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 64
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Bold
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Italic
+%%IncludeResource: font Symbol
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Italic@0 ENC0/Times-Italic RE
+/Times-Roman@0 ENC0/Times-Roman RE/Times-Bold@0 ENC0/Times-Bold RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 16/Times-Bold@0 SF(SENDMAIL)244.888 143.4 Q/F1 12/Times-Bold@0 SF(INST)
+170.172 172.2 Q(ALLA)-1.08 E(TION AND OPERA)-1.14 E(TION GUIDE)-1.14 E/F2 10
+/Times-Roman@0 SF(Eric Allman)263.42 196.2 Q(Uni)219.725 208.2 Q -.15(ve)-.25 G
+(rsity of California, Berk).15 E(ele)-.1 E(y)-.15 E(Mammoth Project)251.75
+220.2 Q(eric@CS.Berk)239.41 232.2 Q(ele)-.1 E -.65(y.)-.15 G(EDU).65 E -1.11
+(Ve)262.725 256.2 S(rsion 8.36)1.11 E -.15(Fo)236.965 280.2 S 2.5(rS).15 G
+(endmail V)258.765 280.2 Q(ersion 8.6)-1.11 E/F3 10/Times-Italic@0 SF(Sendmail)
+97 324.6 Q F2 .699(implements a general purpose internetw)3.199 F .698
+(ork mail routing f)-.1 F .698(acility under the UNIX* operat-)-.1 F .378
+(ing system.)72 336.6 R .378(It is not tied to an)5.378 F 2.878(yo)-.15 G .378
+(ne transport protocol \212 its function may be lik)208.214 336.6 R .378
+(ened to a crossbar switch,)-.1 F 1.036
+(relaying messages from one domain into another)72 348.6 R 6.036(.I)-.55 G
+3.536(nt)284.502 348.6 S 1.036
+(he process, it can do a limited amount of message)295.818 348.6 R .604(header\
+ editing to put the message into a format that is appropriate for the recei)72
+360.6 R .604(ving domain.)-.25 F .604(All of this is)5.604 F
+(done under the control of a con\214guration \214le.)72 372.6 Q .711
+(Due to the requirements of \215e)97 388.8 R .711(xibility for)-.15 F F3
+(sendmail)3.211 E F2 3.211(,t)C .71(he con\214guration \214le can seem some)
+311.688 388.8 R .71(what unap-)-.25 F 2.893(proachable. Ho)72 400.8 R(we)-.25 E
+-.15(ve)-.25 G 1.193 -.4(r, t).15 H .393(here are only a fe).4 F 2.893(wb)-.25
+G .394(asic con\214gurations for most sites, for which standard con\214gu-)
+253.381 400.8 R .646(ration \214les ha)72 412.8 R .946 -.15(ve b)-.2 H .646
+(een supplied.).15 F .645(Most other con\214gurations can be b)5.646 F .645
+(uilt by adjusting an e)-.2 F .645(xisting con\214gura-)-.15 F
+(tion \214les incrementally)72 424.8 Q(.)-.65 E F3(Sendmail)97 441 Q F2 .15
+(is based on RFC822 \(Internet Mail F)2.65 F .15
+(ormat Protocol\), RFC821 \(Simple Mail T)-.15 F .15(ransport Pro-)-.35 F .129
+(tocol\), RFC1123 \(Internet Host Requirements\), and RFC1425 \(SMTP Service E\
+xtensions\).)72 453 R(Ho)5.129 E(we)-.25 E -.15(ve)-.25 G .929 -.4(r, s).15 H
+(ince).4 E F3(sendmail)72 465 Q F2 .749(is designed to w)3.249 F .749
+(ork in a wider w)-.1 F .749(orld, in man)-.1 F 3.25(yc)-.15 G .75
+(ases it can be con\214gured to e)309.31 465 R .75(xceed these proto-)-.15 F
+2.5(cols. These)72 477 R(cases are described herein.)2.5 E(Although)97 493.2 Q
+F3(sendmail)3.548 E F2 1.047(is intended to run without the need for monitorin\
+g, it has a number of features)3.548 F 1.972(that may be used to monitor or ad\
+just the operation under unusual circumstances.)72 505.2 R 1.972
+(These features are)6.972 F(described.)72 517.2 Q .817
+(Section one describes ho)97 533.4 R 3.317(wt)-.25 G 3.317(od)211.668 533.4 S
+3.317(oa)224.985 533.4 S(basic)-.001 E F3(sendmail)3.316 E F2 3.316
+(installation. Section)3.316 F(tw)3.316 E 3.316(oe)-.1 G .816
+(xplains the day-to-day)412.938 533.4 R .282(information you should kno)72
+545.4 R 2.782(wt)-.25 G 2.782(om)196.768 545.4 S .282
+(aintain your mail system.)212.33 545.4 R .282(If you ha)5.282 F .583 -.15
+(ve a r)-.2 H(elati).15 E -.15(ve)-.25 G .283(ly normal site, these tw).15 F(o)
+-.1 E .635(sections should contain suf)72 557.4 R .635
+(\214cient information for you to install)-.25 F F3(sendmail)3.135 E F2 .634
+(and k)3.135 F .634(eep it happ)-.1 F 4.434 -.65(y. S)-.1 H .634(ection three)
+.65 F .925(describes some parameters that may be safely tweak)72 569.4 R 3.425
+(ed. Section)-.1 F .925(four has information re)3.425 F -.05(ga)-.15 G .925
+(rding the com-).05 F .886(mand line ar)72 581.4 R 3.386(guments. Section)-.18
+F<8c76>3.386 E 3.386(ec)-.15 G .885
+(ontains the nitty-gritty information about the con\214guration \214le.)221.92
+581.4 R(This)5.885 E .004
+(section is for masochists and people who must write their o)72 593.4 R .005
+(wn con\214guration \214le.)-.25 F .005(Section six describes con-)5.005 F .886
+(\214guration that can be done at compile time.)72 605.4 R .886(Section se)
+5.886 F -.15(ve)-.25 G 3.386(ng).15 G -2.15 -.25(iv e)322.1 605.4 T 3.386(sab)
+.25 G .886(rief description of dif)354.022 605.4 R .885(ferences in this)-.25 F
+-.15(ve)72 617.4 S 1.619(rsion of).15 F F3(sendmail)4.119 E F2 6.619(.T)C 1.619
+(he appendix)169.197 617.4 R 1.619(es gi)-.15 F 1.919 -.15(ve a b)-.25 H 1.619
+(rief b).15 F 1.619(ut detailed e)-.2 F 1.62
+(xplanation of a number of features not)-.15 F
+(described in the rest of the paper)72 629.4 Q(.)-.55 E .32 LW 76 680.4 72
+680.4 DL 80 680.4 76 680.4 DL 84 680.4 80 680.4 DL 88 680.4 84 680.4 DL 92
+680.4 88 680.4 DL 96 680.4 92 680.4 DL 100 680.4 96 680.4 DL 104 680.4 100
+680.4 DL 108 680.4 104 680.4 DL 112 680.4 108 680.4 DL 116 680.4 112 680.4 DL
+120 680.4 116 680.4 DL 124 680.4 120 680.4 DL 128 680.4 124 680.4 DL 132 680.4
+128 680.4 DL 136 680.4 132 680.4 DL 140 680.4 136 680.4 DL 144 680.4 140 680.4
+DL 148 680.4 144 680.4 DL 152 680.4 148 680.4 DL 156 680.4 152 680.4 DL 160
+680.4 156 680.4 DL 164 680.4 160 680.4 DL 168 680.4 164 680.4 DL 172 680.4 168
+680.4 DL 176 680.4 172 680.4 DL 180 680.4 176 680.4 DL 184 680.4 180 680.4 DL
+188 680.4 184 680.4 DL 192 680.4 188 680.4 DL 196 680.4 192 680.4 DL 200 680.4
+196 680.4 DL 204 680.4 200 680.4 DL 208 680.4 204 680.4 DL 212 680.4 208 680.4
+DL 216 680.4 212 680.4 DL/F4 8/Times-Roman@0 SF
+(*UNIX is a trademark of Unix Systems Laboratories.)93.6 692.4 Q/F5 10
+/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 756 Q(SMM:08-1)
+457.9 756 Q EP
+%%Page: 7 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-7)457.9 60 Q 2.5(1. B)72 96 R(ASIC INST)-.3 E(ALLA)-.9 E(TION)-.95 E/F1
+10/Times-Roman@0 SF .234(There are tw)112 112.2 R 2.733(ob)-.1 G .233
+(asic steps to installing)175.631 112.2 R/F2 10/Times-Italic@0 SF(sendmail)
+2.733 E F1 5.233(.T)C .233(he hard part is to b)317.076 112.2 R .233
+(uild the con\214guration table.)-.2 F 1.185(This is a \214le that)87 124.2 R
+F2(sendmail)3.686 E F1 1.186
+(reads when it starts up that describes the mailers it kno)3.686 F 1.186
+(ws about, ho)-.25 F 3.686(wt)-.25 G(o)499 124.2 Q .715(parse addresses, ho)87
+136.2 R 3.215(wt)-.25 G 3.215(or)178.315 136.2 S -.25(ew)189.86 136.2 S .715
+(rite the message header).25 F 3.215(,a)-.4 G .715(nd the settings of v)306.75
+136.2 R .714(arious options.)-.25 F .714(Although the)5.714 F .852
+(con\214guration table is quite comple)87 148.2 R .852
+(x, a con\214guration can usually be b)-.15 F .852(uilt by adjusting an e)-.2 F
+.852(xisting of)-.15 F(f-)-.25 E 1.078(the-shelf con\214guration.)87 160.2 R
+1.078(The second part is actually doing the installation, i.e., creating the n\
+ecessary)6.078 F(\214les, etc.)87 172.2 Q .192
+(The remainder of this section will describe the installation of)112 188.4 R F2
+(sendmail)2.692 E F1 .192(assuming you can use one)2.692 F 1.432(of the e)87
+200.4 R 1.432(xisting con\214gurations and that the standard installation para\
+meters are acceptable.)-.15 F 1.431(All path-)6.431 F 8.62(names and e)87 212.4
+R 8.62(xamples are gi)-.15 F -.15(ve)-.25 G 11.12(nf).15 G 8.62
+(rom the root of the)257.57 212.4 R F2(sendmail)378.16 212.4 Q F1 8.62
+(subtree, normally)425.39 212.4 R F2(/usr/sr)87 224.4 Q(c/usr)-.37 E
+(.sbin/sendmail)-1.11 E F1(on 4.4BSD.)2.5 E .543(If you are loading this of)112
+240.6 R 3.042(ft)-.25 G .542(he tape, continue with the ne)222.766 240.6 R .542
+(xt section.)-.15 F .542(If you ha)5.542 F .842 -.15(ve a r)-.2 H .542
+(unning binary).15 F
+(already on your system, you should probably skip to section 1.2.)87 252.6 Q F0
+2.5(1.1. Compiling)87 276.6 R(Sendmail)2.5 E F1(All)127 292.8 Q F2(sendmail)
+2.934 E F1 .434(source is in the)2.934 F F2(sr)2.934 E(c)-.37 E F1
+(subdirectory)2.934 E 5.434(.I)-.65 G 2.934(fy)321.652 292.8 S .435
+(ou are running on a 4.4BSD system, com-)332.916 292.8 R
+(pile by typing \231mak)102 304.8 Q 2.5(e\232. On)-.1 F
+(other systems, you may ha)2.5 E .3 -.15(ve t)-.2 H 2.5(om).15 G(ak)348.75
+304.8 Q 2.5(es)-.1 G(ome other adjustments.)368.92 304.8 Q F0 2.5(1.1.1. Old)
+102 328.8 R -.1(ve)2.5 G(rsions of mak).1 E(e)-.1 E F1
+(If you are not running the ne)142 345 Q 2.5(wv)-.25 G(ersion of)270.74 345 Q
+F0(mak)2.5 E(e)-.1 E F1(you will probably ha)2.5 E .3 -.15(ve t)-.2 H 2.5(ou)
+.15 G(se)444.16 345 Q(mak)157 361.2 Q 2.5<65ad>-.1 G 2.5(fM)186.7 361.2 S(ak)
+201.42 361.2 Q(e\214le.dist)-.1 E .885(This \214le does not assume se)117 377.4
+R -.15(ve)-.25 G .885(ral ne).15 F 3.385(ws)-.25 G(yntax)280.025 377.4 Q .885
+(es, including the \231+=\232 syntax in macro de\214nition)-.15 F
+(and the \231.include\232 syntax.)117 389.4 Q F0 2.5(1.1.2. Compilation)102
+413.4 R(\215ags)2.5 E F2(Sendmail)142 429.6 Q F1(supports tw)2.5 E 2.5(od)-.1 G
+(if)240.51 429.6 Q(ferent formats for the)-.25 E F2(aliases)2.5 E F1 2.5
+(database. These)2.5 F(formats are:)2.5 E 39.5(NDBM The)117 445.8 R -.74(``)
+3.166 G(ne).74 E 3.166(wD)-.25 G(BM')240.432 445.8 Q 3.166('f)-.74 G .666
+(ormat, a)268.408 445.8 R -.25(va)-.2 G .666
+(ilable on nearly all systems around today).25 F 5.667(.T)-.65 G(his)492.33
+445.8 Q -.1(wa)189 457.8 S 3.541(st).1 G 1.041
+(he preferred format prior to 4.4BSD.)210.771 457.8 R 1.041(It allo)6.041 F
+1.041(ws such comple)-.25 F 3.54(xt)-.15 G 1.04(hings as)470.46 457.8 R
+(multiple databases and closing a currently open database.)189 469.8 Q 32.84
+(NEWDB The)117 486 R(ne)3.323 E 3.323(wd)-.25 G .824(atabase package from Berk)
+232.606 486 R(ele)-.1 E 4.624 -.65(y. I)-.15 H 3.324(fy).65 G .824(ou ha)
+382.716 486 R 1.124 -.15(ve t)-.2 H .824(his, use it.).15 F .824(It allo)5.824
+F(ws)-.25 E .839
+(long records, multiple open databases, real in-memory caching, and so forth.)
+189 498 R -1.1(Yo)189 510 S 3.581(uc)1.1 G 1.081
+(an de\214ne this in conjunction with one of the other tw)213.141 510 R 1.082
+(o; if you do, old)-.1 F .693(databases are read, b)189 522 R .693
+(ut when a ne)-.2 F 3.193(wd)-.25 G .693
+(atabase is created it will be in NEWDB)341.681 522 R 2.851(format. As)189 534
+R 2.851(an)2.851 G .351(asty hack, if you ha)249.763 534 R .652 -.15(ve N)-.2 H
+.352(EWDB, NDBM, and NIS de\214ned, and).15 F 1.593(if the \214le)189 546 R F2
+(/var/yp/Mak)4.093 E(e\214le)-.1 E F1 -.15(ex)4.093 G 1.593
+(ists and is readable,).15 F F2(sendmail)4.093 E F1 1.592(will create both)
+4.092 F(ne)189 558 Q 3.975(wa)-.25 G 1.475(nd old v)213.825 558 R 1.475
+(ersions of the alias \214le during a)-.15 F F2(ne)3.976 E(walias)-.15 E F1
+3.976(command. This)3.976 F(is)3.976 E .711
+(required because the Sun NIS/YP system reads the DBM v)189 570 R .71
+(ersion of the alias)-.15 F 2.5(\214le. It')189 582 R 2.5(su)-.55 G
+(gly as sin, b)229.56 582 Q(ut it w)-.2 E(orks.)-.1 E 1.112
+(If neither of these are de\214ned,)117 598.2 R F2(sendmail)3.612 E F1 1.112
+(reads the alias \214le into memory on e)3.612 F -.15(ve)-.25 G 1.112(ry in).15
+F -.2(vo)-.4 G(cation.).2 E(This can be slo)117 610.2 Q 2.5(wa)-.25 G
+(nd should be a)191.18 610.2 Q -.2(vo)-.2 G(ided.).2 E .719
+(System V based systems can de\214ne SYSTEM5 to mak)142 626.4 R 3.219(es)-.1 G
+-2.15 -.25(ev e)378.083 626.4 T .719(ral small adjustments.).25 F(This)5.719 E
+1.076(changes the handling of timezones and uses the much less ef)117 638.4 R
+(\214cient)-.25 E F2(loc)3.576 E(kf)-.2 E F1 1.076(call in preference to)3.576
+F F2(\215oc)117 650.4 Q(k)-.2 E F1 7.225(.T)C 2.224(hese can be speci\214ed se\
+parately using the compilation \215ags SYS5TZ and LOCKF)151.515 650.4 R
+(respecti)117 662.4 Q -.15(ve)-.25 G(ly).15 E(.)-.65 E 1.646(If you don')142
+678.6 R 4.147(th)-.18 G -2.25 -.2(av e)202.03 678.6 T(the)4.347 E F2(unseten)
+4.147 E(v)-.4 E F1 1.647(routine in your system library)4.147 F 4.147(,d)-.65 G
+1.647(e\214ne the UNSETENV)411.276 678.6 R(compilation \215ag.)117 690.6 Q -1.1
+(Yo)142 706.8 S 3.855(um)1.1 G 1.355(ay also ha)169.755 706.8 R 1.655 -.15
+(ve t)-.2 H 3.855(od).15 G 1.355(e\214ne the compilation v)242.035 706.8 R
+1.354(ariable LA_TYPE to describe ho)-.25 F 3.854(wy)-.25 G(our)490.67 706.8 Q
+(load a)117 718.8 Q -.15(ve)-.2 G(rage is computed.).15 E
+(This and other \215ags are detailed in section 6.1.)5 E EP
+%%Page: 8 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 198.36(SMM:08-8 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(1.1.3. Compilation)102 96 R
+(and installation)2.5 E/F1 10/Times-Roman@0 SF .308
+(After making the local system con\214guration described abo)142 112.2 R -.15
+(ve)-.15 G 2.809(,Y).15 G .309(ou should be able to com-)398.855 112.2 R .87
+(pile and install the system.)117 126.2 R .87
+(Compilation can be performed using \231mak)5.87 F(e)-.1 E/F2 7/Times-Roman@0
+SF(1)412.24 122.2 Q F1 3.37<9a69>415.74 126.2 S 3.37(nt)426.33 126.2 S(he)
+437.48 126.2 Q F0(sendmail/sr)3.37 E(c)-.18 E F1(directory)117 138.2 Q 5(.Y)
+-.65 G(ou may be able to install using)166.07 138.2 Q(mak)157 154.4 Q 2.5(ei)
+-.1 G(nstall)183.84 154.4 Q 3.346
+(This should install the binary in /usr/sbin and create links from /usr/bin/ne)
+117 170.6 R -.1(wa)-.25 G 3.346(liases and).1 F 1.577
+(/usr/bin/mailq to /usr/sbin/sendmail.)117 182.6 R 1.577
+(On 4.4BSD systems it will also format and install man)6.577 F(pages.)117 194.6
+Q F0 2.5(1.2. Con\214guration)87 218.6 R(Files)2.5 E/F3 10/Times-Italic@0 SF
+(Sendmail)127 234.8 Q F1 .355(cannot operate without a con\214guration \214le.)
+2.855 F .355(The con\214guration de\214nes the mail sys-)5.355 F .286
+(tems understood at this site, ho)102 246.8 R 2.786(wt)-.25 G 2.786(oa)239.856
+246.8 S .286(ccess them, ho)252.082 246.8 R 2.786(wt)-.25 G 2.786(of)323.79
+246.8 S(orw)334.906 246.8 Q .286(ard email to remote mail systems, and)-.1 F
+3.113(an)102 258.8 S .613(umber of tuning parameters.)114.553 258.8 R .614
+(This con\214guration \214le is detailed in the later portion of this docu-)
+5.614 F(ment.)102 270.8 Q(The)127 287 Q F3(sendmail)2.764 E F1 .264
+(con\214guration can be daunting at \214rst.)2.764 F .264(The w)5.264 F .264
+(orld is comple)-.1 F .264(x, and the mail con-)-.15 F .108
+(\214guration re\215ects that.)102 299 R .108(The distrib)5.108 F .109
+(ution includes an m4-based con\214guration package that hides a lot)-.2 F
+(of the comple)102 311 Q(xity)-.15 E(.)-.65 E .47
+(These con\214guration \214les are simpler than old v)127 327.2 R .47
+(ersions lar)-.15 F .47(gely because the w)-.18 F .47(orld has become)-.1 F
+1.448(simpler; in particular)102 339.2 R 3.948(,t)-.4 G -.15(ex)197.604 339.2 S
+1.448(t-based host \214les are of).15 F 1.449(\214cially eliminated, ob)-.25 F
+1.449(viating the need to \231hide\232)-.15 F(hosts behind a re)102 351.2 Q
+(gistered internet g)-.15 E(ate)-.05 E -.1(wa)-.25 G -.65(y.).1 G .092(These \
+\214les also assume that most of your neighbors use domain-based UUCP addressi\
+ng; that)127 367.4 R .361(is, instead of naming hosts as \231host!user\232 the)
+102 379.4 R 2.861(yw)-.15 G .361(ill use \231host.domain!user\232.)299.435
+379.4 R .361(The con\214guration \214les)5.361 F(can be customized to w)102
+391.4 Q(ork around this, b)-.1 E(ut it is more comple)-.2 E(x.)-.15 E 2.828(Ih)
+127 407.6 S -2.25 -.2(av e)138.158 407.6 T(n').2 E 2.828(tt)-.18 G .328
+(ested these yet on an isolated LAN en)168.226 407.6 R .328
+(vironment with a single UUCP connection to)-.4 F 4.408(the outside w)102 419.6
+R 6.908(orld. If)-.1 F 4.409(you are in such an en)6.908 F 4.409
+(vironment, please send comments to send-)-.4 F(mail@CS.Berk)102 431.6 Q(ele)
+-.1 E -.65(y.)-.15 G(EDU.).65 E .658
+(Our con\214guration \214les are processed by)127 447.8 R F3(m4)3.158 E F1 .658
+(to f)3.158 F .657(acilitate local customization; the directory)-.1 F F3(cf)
+3.157 E F1 .396(of the)102 459.8 R F3(sendmail)2.896 E F1(distrib)2.896 E .396
+(ution directory contains the source \214les.)-.2 F .396
+(This directory contains se)5.396 F -.15(ve)-.25 G .397(ral sub-).15 F
+(directories:)102 471.8 Q 61.73(cf Both)102 488 R .56
+(site-dependent and site-independent descriptions of hosts.)3.06 F .56
+(These can be lit-)5.56 F .445(eral host names \(e.g., \231ucb)174 500 R -.25
+(va)-.15 G .445(x.mc\232\) when the hosts are g).25 F(ate)-.05 E -.1(wa)-.25 G
+.445(ys or more general).1 F 3.589(descriptions \(such as \231tcpproto.mc\232 \
+as a general description of an SMTP-)174 512 R .536(connected host or \231uucp\
+proto.mc\232 as a general description of a UUCP-connected)174 524 R 3.291
+(host\). Files)174 536 R(ending)3.291 E F0(.mc)3.291 E F1(\(`)3.291 E .791
+(`Master Con\214guration')-.74 F .791('\) are the input descriptions; the)-.74
+F 2.14(output is in the corresponding)174 548 R F0(.cf)4.64 E F1 4.64
+(\214le. The)4.64 F 2.14(general structure of these \214les is)4.64 F
+(described belo)174 560 Q -.65(w.)-.25 G 39.5(domain Site-dependent)102 576.2 R
+.428(subdomain descriptions.)2.928 F .428(These are tied to the w)5.428 F .428
+(ay your or)-.1 F -.05(ga)-.18 G(niza-).05 E .292(tion w)174 588.2 R .292
+(ants to do addressing.)-.1 F -.15(Fo)5.292 G 2.792(re).15 G(xample,)313.122
+588.2 Q F0(domain/cs.exposed.m4)2.792 E F1 .292(is our descrip-)2.792 F .443
+(tion for hosts in the CS.Berk)174 600.2 R(ele)-.1 E -.65(y.)-.15 G .443
+(EDU subdomain that w).65 F .442(ant their indi)-.1 F .442(vidual host-)-.25 F
+.962(name to be e)174 612.2 R .963(xternally visible;)-.15 F F0
+(domain/cs.hidden.m4)3.463 E F1 .963(is the same e)3.463 F .963(xcept that the)
+-.15 F 2.628(hostname is hidden \(e)174 624.2 R -.15(ve)-.25 G 2.628
+(rything looks lik).15 F 5.128(ei)-.1 G 5.128(tc)362.038 624.2 S 2.627
+(omes from CS.Berk)374.386 624.2 R(ele)-.1 E -.65(y.)-.15 G(EDU\).).65 E
+(These are referenced using the)174 636.2 Q/F4 9/Times-Roman@0 SF(DOMAIN)2.5 E
+F0(m4)2.5 E F1(macro in the)2.5 E F0(.mc)2.5 E F1(\214le.)2.5 E 41.74
+(feature De\214nitions)102 652.4 R .728
+(of speci\214c features that some particular host in your site might w)3.228 F
+(ant.)-.1 E 2.467(These are referenced using the)174 664.4 R F4(FEA)4.966 E
+(TURE)-.999 E F0(m4)4.966 E F1 4.966(macro. An)4.966 F -.15(ex)4.966 G 2.466
+(ample feature is).15 F 1.316(use_cw_\214le \(which tells)174 676.4 R F3
+(sendmail)3.816 E F1 1.317(to read an /etc/sendmail.cw \214le on startup to)
+3.816 F .32 LW 76 686 72 686 DL 80 686 76 686 DL 84 686 80 686 DL 88 686 84 686
+DL 92 686 88 686 DL 96 686 92 686 DL 100 686 96 686 DL 104 686 100 686 DL 108
+686 104 686 DL 112 686 108 686 DL 116 686 112 686 DL 120 686 116 686 DL 124 686
+120 686 DL 128 686 124 686 DL 132 686 128 686 DL 136 686 132 686 DL 140 686 136
+686 DL 144 686 140 686 DL 148 686 144 686 DL 152 686 148 686 DL 156 686 152 686
+DL 160 686 156 686 DL 164 686 160 686 DL 168 686 164 686 DL 172 686 168 686 DL
+176 686 172 686 DL 180 686 176 686 DL 184 686 180 686 DL 188 686 184 686 DL 192
+686 188 686 DL 196 686 192 686 DL 200 686 196 686 DL 204 686 200 686 DL 208 686
+204 686 DL 212 686 208 686 DL 216 686 212 686 DL/F5 5/Times-Roman@0 SF(1)93.6
+696.4 Q/F6 8/Times-Roman@0 SF(where you may ha)3.2 I .24 -.12(ve t)-.16 H 2(or)
+.12 G(eplace \231mak)175.132 699.6 Q(e\232 with \231mak)-.08 E 2<65ad>-.08 G 2
+(fM)267.452 699.6 S(ak)279.228 699.6 Q(e\214le.dist\232 as appropriate.)-.08 E
+EP
+%%Page: 9 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-9)457.9 60 Q/F1 10/Times-Roman@0 SF(\214nd the set of local names\).)
+174 96 Q 50.62(hack Local)102 112.2 R 1.886(hacks, referenced using the)4.387 F
+/F2 9/Times-Roman@0 SF(HA)4.386 E(CK)-.36 E F0(m4)4.386 E F1 4.386(macro. T)
+4.386 F 1.886(ry to a)-.35 F -.2(vo)-.2 G 1.886(id these.).2 F(The)6.886 E
+(point of ha)174 124.2 Q(ving them here is to mak)-.2 E 2.5(ei)-.1 G 2.5(tc)
+325.91 124.2 S(lear that the)335.63 124.2 Q 2.5(ys)-.15 G(mell.)394.08 124.2 Q
+56.72(m4 Site-independent)102 140.4 R/F3 10/Times-Italic@0 SF(m4)2.538 E F1
+.038(\(1\) include \214les that ha)B .338 -.15(ve i)-.2 H .038
+(nformation common to all con\214gu-).15 F(ration \214les.)174 152.4 Q
+(This can be thought of as a \231#include\232 directory)5 E(.)-.65 E 43.95
+(mailer De\214nitions)102 168.6 R .918(of mailers, referenced using the)3.418 F
+F2(MAILER)3.417 E F0(m4)3.417 E F1 3.417(macro. De\214ned)3.417 F(mailer)3.417
+E(types in this distrib)174 180.6 Q(ution are f)-.2 E
+(ax, local, smtp, uucp, and usenet.)-.1 E 43.39(ostype De\214nitions)102 196.8
+R 1.156(describing v)3.656 F 1.157(arious operating system en)-.25 F 1.157
+(vironments \(such as the loca-)-.4 F(tion of support \214les\).)174 208.8 Q
+(These are referenced using the)5 E F2(OSTYPE)2.5 E F0(m4)2.5 E F1(macro.)2.5 E
+60.61(sh Shell)102 225 R(\214les used by the)2.5 E F0(m4)2.5 E F1 -.2(bu)2.5 G
+(ild process.).2 E -1.1(Yo)5 G 2.5(us)1.1 G(houldn')362.97 225 Q 2.5(th)-.18 G
+-2.25 -.2(av e)404.18 225 T(to mess with these.)2.7 E 30.61(sitecon\214g Local)
+102 241.2 R .49(site con\214guration information, such as UUCP connecti)2.99 F
+(vity)-.25 E 5.49(.T)-.65 G(he)450.61 241.2 Q 2.99(yn)-.15 G(ormally)472.89
+241.2 Q(contain lists of site information, for e)174 253.2 Q(xample:)-.15 E
+(SITE\(contessa\))214 269.4 Q(SITE\(hoptoad\))214 281.4 Q(SITE\(nkainc\))214
+293.4 Q(SITE\(well\))214 305.4 Q(The)174 321.6 Q 2.5(ya)-.15 G
+(re referenced using the SITECONFIG macro:)201.34 321.6 Q
+(SITECONFIG\(site.con\214g.\214le, name_of_site, X\))214 337.8 Q(where)174 354
+Q F3(X)2.703 E F1 .203(is the macro/class name to use.)2.703 F .204
+(It can be U \(indicating locally connected)5.204 F(hosts\) or one of W)174 366
+Q 2.5(,X)-.92 G 2.5(,o)259.73 366 S 2.5(rYf)269.73 366 S
+(or up to three remote UUCP hubs.)288.61 366 Q .757(If you are in a ne)127
+382.2 R 3.257(wd)-.25 G .757(omain \(e.g., a compan)214.042 382.2 R .756
+(y\), you will probably w)-.15 F .756(ant to create a cf/domain)-.1 F .87
+(\214le for your domain.)102 394.2 R .871
+(This consists primarily of relay de\214nitions: for e)5.871 F .871
+(xample, Berk)-.15 F(ele)-.1 E(y')-.15 E 3.371(sd)-.55 G(omain)479 394.2 Q .16
+(de\214nition de\214nes relays for BitNET)102 406.2 R 2.66(,C)-.74 G(SNET)
+257.61 406.2 Q 2.66(,a)-.74 G .16(nd UUCP)291.47 406.2 R 5.16(.O)-1.11 G 2.66
+(ft)344.57 406.2 S .16(hese, only the UUCP relay is particu-)353.34 406.2 R .46
+(larly speci\214c to Berk)102 418.2 R(ele)-.1 E 4.26 -.65(y. A)-.15 H .46
+(ll of these are internet-style domain names.).65 F .46(Please check to mak)
+5.46 F 2.96(ec)-.1 G(er)493.1 418.2 Q(-)-.2 E(tain the)102 430.2 Q 2.5(ya)-.15
+G(re reasonable for your domain.)143.51 430.2 Q 1.407(Subdomains at Berk)127
+446.4 R(ele)-.1 E 3.907(ya)-.15 G 1.407
+(re also represented in the cf/domain directory)235.681 446.4 R 6.406(.F)-.65 G
+1.406(or e)439.408 446.4 R 1.406(xample, the)-.15 F 1.49(domain cs-e)102 458.4
+R 1.491(xposed is the Computer Science subdomain with the local hostname sho)
+-.15 F 1.491(wn to other)-.25 F 1.411(users; cs-hidden mak)102 470.4 R 1.411
+(es users appear to be from the CS.Berk)-.1 F(ele)-.1 E -.65(y.)-.15 G 1.41
+(EDU subdomain \(with no local).65 F 1.083(host information included\).)102
+482.4 R -1.1(Yo)6.083 G 3.583(uw)1.1 G 1.083(ill probably ha)246.332 482.4 R
+1.384 -.15(ve t)-.2 H 3.584(ou).15 G 1.084
+(pdate this directory to be appropriate for)335.866 482.4 R(your domain.)102
+494.4 Q -1.1(Yo)127 510.6 S 4.373(uw)1.1 G 1.873(ill ha)154.713 510.6 R 2.173
+-.15(ve t)-.2 H 4.373(ou).15 G 1.873(se or create)207.482 510.6 R F0(.mc)4.372
+E F1 1.872(\214les in the)4.372 F F3(cf/cf)4.372 E F1 1.872
+(subdirectory for your hosts.)4.372 F 1.872(This is)6.872 F
+(detailed in the cf/README \214le.)102 522.6 Q F0 2.5(1.3. Details)87 546.6 R
+(of Installation Files)2.5 E F1
+(This subsection describes the \214les that comprise the)127 562.8 Q F3
+(sendmail)2.5 E F1(installation.)2.5 E F0 2.5(1.3.1. /usr/sbin/sendmail)102
+586.8 R F1 .08(The binary for)142 605 R F3(sendmail)2.58 E F1 .079
+(is located in /usr/sbin)2.58 F/F4 7/Times-Roman@0 SF(2)326.708 601 Q F1 5.079
+(.I)330.208 605 S 2.579(ts)341.117 605 S .079(hould be setuid root.)350.366 605
+R -.15(Fo)5.079 G 2.579(rs).15 G .079(ecurity rea-)458.111 605 R(sons, /, /usr)
+117 619 Q 2.5(,a)-.4 G(nd /usr/sbin should be o)171.6 619 Q
+(wned by root, mode 755)-.25 E F4(3)364.4 615 Q F1(.)367.9 619 Q .32 LW 76 646
+72 646 DL 80 646 76 646 DL 84 646 80 646 DL 88 646 84 646 DL 92 646 88 646 DL
+96 646 92 646 DL 100 646 96 646 DL 104 646 100 646 DL 108 646 104 646 DL 112
+646 108 646 DL 116 646 112 646 DL 120 646 116 646 DL 124 646 120 646 DL 128 646
+124 646 DL 132 646 128 646 DL 136 646 132 646 DL 140 646 136 646 DL 144 646 140
+646 DL 148 646 144 646 DL 152 646 148 646 DL 156 646 152 646 DL 160 646 156 646
+DL 164 646 160 646 DL 168 646 164 646 DL 172 646 168 646 DL 176 646 172 646 DL
+180 646 176 646 DL 184 646 180 646 DL 188 646 184 646 DL 192 646 188 646 DL 196
+646 192 646 DL 200 646 196 646 DL 204 646 200 646 DL 208 646 204 646 DL 212 646
+208 646 DL 216 646 212 646 DL/F5 5/Times-Roman@0 SF(2)93.6 656.4 Q/F6 8
+/Times-Roman@0 SF .384(This is usually /usr/sbin on 4.4BSD and ne)3.2 J .384
+(wer systems; man)-.2 F 2.385(ys)-.12 G .385(ystems install it in /usr/lib)
+302.957 659.6 R 4.385(.I)-.32 G .385(understand it is in /usr/ucblib on)398.739
+659.6 R(System V Release 4.)72 669.2 Q F5(3)93.6 679.6 Q F6 .149(Some v)3.2 J
+.15(endors ship them o)-.12 F .15
+(wned by bin; this creates a security hole that is not actually related to)-.2
+F/F7 8/Times-Italic@0 SF(sendmail)2.15 E F6 4.15(.O)C .15(ther important di-)
+447.26 682.8 R(rectories that should ha)72 692.4 Q .24 -.12(ve r)-.16 H
+(estricti).12 E .24 -.12(ve o)-.2 H(wnerships and permissions are /bin, /usr/b\
+in, /etc, /usr/etc, /lib, and /usr/lib)-.08 E(.)-.32 E EP
+%%Page: 10 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-10 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(1.3.2. /etc/sendmail.cf)102 96 R/F1
+10/Times-Roman@0 SF .025(This is the con\214guration \214le for)142 112.2 R/F2
+10/Times-Italic@0 SF(sendmail)2.525 E F1 5.025(.T)C .025
+(his is the only non-library \214le name compiled)321.335 112.2 R(into)117
+126.2 Q F2(sendmail)2.5 E/F3 7/Times-Roman@0 SF(4)171.17 122.2 Q F1 5(.S)174.67
+126.2 S(ome older systems install it in)187.73 126.2 Q F0(/usr/lib/sendmail.cf)
+2.5 E F1(.)A(If you w)142 142.4 Q(ant to mo)-.1 E .3 -.15(ve t)-.15 H
+(his \214le, change).15 E F2(sr)2.5 E(c/pathnames.h)-.37 E F1(.)A .721
+(The con\214guration \214le is normally created using the distrib)142 158.6 R
+.721(ution \214les described abo)-.2 F -.15(ve)-.15 G 5.72(.I).15 G(f)500.67
+158.6 Q .64(you ha)117 170.6 R .94 -.15(ve a p)-.2 H .64
+(articularly unusual system con\214guration you may need to create a special v)
+.15 F(ersion.)-.15 E
+(The format of this \214le is detailed in later sections of this document.)117
+182.6 Q F0 2.5(1.3.3. /usr/bin/newaliases)102 206.6 R F1(The)142 222.8 Q F2(ne)
+2.5 E(waliases)-.15 E F1(command should just be a link to)2.5 E F2(sendmail)2.5
+E F1(:)A(rm \255f /usr/bin/ne)157 239 Q -.1(wa)-.25 G(liases).1 E
+(ln \255s /usr/sbin/sendmail /usr/bin/ne)157 251 Q -.1(wa)-.25 G(liases).1 E
+(This can be installed in whate)117 267.2 Q -.15(ve)-.25 G 2.5(rs).15 G
+(earch path you prefer for your system.)254.91 267.2 Q F0 2.5(1.3.4. /v)102
+291.2 R(ar/spool/mqueue)-.1 E F1 .218(The directory)142 307.4 R F2
+(/var/spool/mqueue)2.718 E F1 .217(should be created to hold the mail queue.)
+2.718 F .217(This directory)5.217 F(should be mode 700 and o)117 319.4 Q
+(wned by root.)-.25 E(The actual path of this directory is de\214ned in the)142
+335.6 Q F0(Q)2.5 E F1(option of the)2.5 E F2(sendmail.cf)2.5 E F1(\214le.)2.5 E
+F0 2.5(1.3.5. /etc/aliases*)102 359.6 R F1 1.492
+(The system aliases are held in \231/etc/aliases\232.)142 375.8 R 3.992(As)
+6.492 G 1.492(ample is gi)350.006 375.8 R -.15(ve)-.25 G 3.993(ni).15 G 3.993
+<6e99>417.694 375.8 S 1.493(lib/aliases\232 which)431.127 375.8 R
+(includes some aliases which)117 387.8 Q F2(must)2.5 E F1(be de\214ned:)2.5 E
+(cp lib/aliases /etc/aliases)157 404 Q F2(edit /etc/aliases)157 416 Q F1 -1.1
+(Yo)117 432.2 S 2.5(us)1.1 G(hould e)139.51 432.2 Q(xtend this \214le with an)
+-.15 E 2.5(ya)-.15 G(liases that are apropos to your system.)267.54 432.2 Q
+(Normally)142 448.4 Q F2(sendmail)3.61 E F1 1.109(looks at a v)3.61 F 1.109
+(ersion of these \214les maintained by the)-.15 F F2(dbm)3.609 E F1 1.109
+(\(3\) or)1.666 F F2(db)3.609 E F1(\(3\))1.666 E 3.46(routines. These)117 460.4
+R .96(are stored either in \231/etc/aliases.dir\232 and \231/etc/aliases.pag\
+\232 or \231/etc/aliases.db\232)3.46 F 1.022
+(depending on which database package you are using.)117 472.4 R 1.022
+(These can initially be created as empty)6.022 F(\214les, b)117 484.4 Q(ut the)
+-.2 E 2.5(yw)-.15 G(ill ha)180.54 484.4 Q .3 -.15(ve t)-.2 H 2.5(ob).15 G 2.5
+(ei)227.69 484.4 S(nitialized promptly)237.41 484.4 Q 5(.T)-.65 G
+(hese should be mode 644:)326.76 484.4 Q(cp /de)157 500.6 Q
+(v/null /etc/aliases.dir)-.25 E(cp /de)157 512.6 Q(v/null /etc/aliases.pag)-.25
+E(chmod 644 /etc/aliases.*)157 524.6 Q(ne)157 536.6 Q -.1(wa)-.25 G(liases).1 E
+(The)117 552.8 Q F2(db)2.79 E F1 .29(routines preset the mode reasonably)2.79 F
+2.79(,s)-.65 G 2.79(ot)301.68 552.8 S .29(his step can be skipped.)312.25 552.8
+R .29(The actual path of this)5.29 F(\214le is de\214ned in the)117 564.8 Q F0
+(A)2.5 E F1(option of the)2.5 E F2(sendmail.cf)2.5 E F1(\214le.)2.5 E F0 2.5
+(1.3.6. /etc/r)102 588.8 R(c)-.18 E F1 .156
+(It will be necessary to start up the)142 605 R F2(sendmail)2.655 E F1 .155
+(daemon when your system reboots.)2.655 F .155(This dae-)5.155 F 1.537
+(mon performs tw)117 617 R 4.037(of)-.1 G 1.537
+(unctions: it listens on the SMTP sock)201.221 617 R 1.537
+(et for connections \(to recei)-.1 F 1.838 -.15(ve m)-.25 H(ail).15 E .442(fro\
+m a remote system\) and it processes the queue periodically to insure that mai\
+l gets deli)117 629 R -.15(ve)-.25 G(red).15 E(when hosts come up.)117 641 Q
+.505(Add the follo)142 657.2 R .505(wing lines to \231/etc/rc\232 \(or \231/et\
+c/rc.local\232 as appropriate\) in the area where it)-.25 F
+(is starting up the daemons:)117 669.2 Q .32 LW 76 678.8 72 678.8 DL 80 678.8
+76 678.8 DL 84 678.8 80 678.8 DL 88 678.8 84 678.8 DL 92 678.8 88 678.8 DL 96
+678.8 92 678.8 DL 100 678.8 96 678.8 DL 104 678.8 100 678.8 DL 108 678.8 104
+678.8 DL 112 678.8 108 678.8 DL 116 678.8 112 678.8 DL 120 678.8 116 678.8 DL
+124 678.8 120 678.8 DL 128 678.8 124 678.8 DL 132 678.8 128 678.8 DL 136 678.8
+132 678.8 DL 140 678.8 136 678.8 DL 144 678.8 140 678.8 DL 148 678.8 144 678.8
+DL 152 678.8 148 678.8 DL 156 678.8 152 678.8 DL 160 678.8 156 678.8 DL 164
+678.8 160 678.8 DL 168 678.8 164 678.8 DL 172 678.8 168 678.8 DL 176 678.8 172
+678.8 DL 180 678.8 176 678.8 DL 184 678.8 180 678.8 DL 188 678.8 184 678.8 DL
+192 678.8 188 678.8 DL 196 678.8 192 678.8 DL 200 678.8 196 678.8 DL 204 678.8
+200 678.8 DL 208 678.8 204 678.8 DL 212 678.8 208 678.8 DL 216 678.8 212 678.8
+DL/F4 5/Times-Roman@0 SF(4)93.6 689.2 Q/F5 8/Times-Roman@0 SF .588
+(The system libraries can reference other \214les; in particular)3.2 J 2.589
+(,s)-.32 G .589(ystem library subroutines that)294.805 692.4 R/F6 8
+/Times-Italic@0 SF(sendmail)2.589 E F5 .589(calls probably reference)2.589 F F6
+(/etc/passwd)72 702 Q F5(and)2 E F6(/etc/r)2 E(esolv)-.296 E(.conf)-.592 E F5
+(.)A EP
+%%Page: 11 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-11)452.9 60 Q/F1 10/Times-Roman@0 SF
+(if [ \255f /usr/sbin/sendmail \255a \255f /etc/sendmail.cf ]; then)157 96 Q
+(\(cd /v)193 108 Q(ar/spool/mqueue; rm \255f [lnx]f*\))-.25 E
+(/usr/sbin/sendmail \255bd \255q30m &)193 120 Q(echo \255n ' sendmail' >/de)193
+132 Q(v/console)-.25 E<8c>157 144 Q .174
+(The \231cd\232 and \231rm\232 commands insure that all lock \214les ha)117
+160.2 R .473 -.15(ve b)-.2 H .173(een remo).15 F -.15(ve)-.15 G .173(d; e).15 F
+.173(xtraneous lock \214les)-.15 F .004
+(may be left around if the system goes do)117 172.2 R .005
+(wn in the middle of processing a message.)-.25 F .005(The line that)5.005 F
+2.294(actually in)117 184.2 R -.2(vo)-.4 G -.1(ke).2 G(s).1 E/F2 10
+/Times-Italic@0 SF(sendmail)4.794 E F1 2.294(has tw)4.794 F 4.794<6f8d>-.1 G
+2.293(ags: \231\255bd\232 causes it to listen on the SMTP port, and)272.94
+184.2 R(\231\255q30m\232 causes it to run the queue e)117 196.2 Q -.15(ve)-.25
+G(ry half hour).15 E(.)-.55 E .378(Some people use a more comple)142 212.4 R
+2.879(xs)-.15 G .379(tartup script, remo)285.209 212.4 R .379
+(ving zero length qf \214les and df \214les)-.15 F
+(for which there is no qf \214le.)117 224.4 Q -.15(Fo)5 G 2.5(re).15 G(xample:)
+253.9 224.4 Q 2.5(#r)157 240.6 S(emo)167.83 240.6 Q .3 -.15(ve z)-.15 H
+(ero length qf \214les).15 E(for qf)157 252.6 Q(\214le in qf*)-.25 E(do)157
+264.6 Q(if [ \255r $qf)193 276.6 Q(\214le ])-.25 E(then)193 288.6 Q
+(if [ ! \255s $qf)229 300.6 Q(\214le ])-.25 E(then)229 312.6 Q
+(echo \255n " <zero: $qf)265 324.6 Q(\214le>" > /de)-.25 E(v/console)-.25 E
+(rm \255f $qf)265 336.6 Q(\214le)-.25 E<8c>229 348.6 Q<8c>193 360.6 Q(done)157
+372.6 Q 2.5(#r)157 384.6 S(ename tf \214les to be qf if the qf does not e)
+167.83 384.6 Q(xist)-.15 E(for tf)157 396.6 Q(\214le in tf*)-.25 E(do)157 408.6
+Q(qf)193 420.6 Q(\214le=`echo $tf)-.25 E(\214le | sed ')-.25 E(s/t/q/'`)-.55 E
+(if [ \255r $tf)193 432.6 Q(\214le \255a ! \255f $qf)-.25 E(\214le ])-.25 E
+(then)193 444.6 Q(echo \255n " <reco)229 456.6 Q -.15(ve)-.15 G(ring: $tf).15 E
+(\214le>" > /de)-.25 E(v/console)-.25 E(mv $tf)229 468.6 Q(\214le $qf)-.25 E
+(\214le)-.25 E(else)193 480.6 Q(echo \255n " <e)229 492.6 Q(xtra: $tf)-.15 E
+(\214le>" > /de)-.25 E(v/console)-.25 E(rm \255f $tf)229 504.6 Q(\214le)-.25 E
+<8c>193 516.6 Q(done)157 528.6 Q 2.5(#r)157 540.6 S(emo)167.83 540.6 Q .3 -.15
+(ve d)-.15 H 2.5<668c>.15 G(les with no corresponding qf \214les)213.08 540.6 Q
+(for df)157 552.6 Q(\214le in df*)-.25 E(do)157 564.6 Q(qf)193 576.6 Q
+(\214le=`echo $df)-.25 E(\214le | sed ')-.25 E(s/d/q/'`)-.55 E(if [ \255r $df)
+193 588.6 Q(\214le \255a ! \255f $qf)-.25 E(\214le ])-.25 E(then)193 600.6 Q
+(echo \255n " <incomplete: $df)229 612.6 Q(\214le>" > /de)-.25 E(v/console)-.25
+E(mv $df)229 624.6 Q(\214le `echo $df)-.25 E(\214le | sed ')-.25 E(s/d/D/'`)
+-.55 E<8c>193 636.6 Q(done)157 648.6 Q 2.5(#a)157 660.6 S
+(nnounce \214les that ha)168.94 660.6 Q .3 -.15(ve b)-.2 H(een sa).15 E -.15
+(ve)-.2 G 2.5(dd).15 G(uring disaster reco)314.32 660.6 Q -.15(ve)-.15 G(ry).15
+E(for xf)157 672.6 Q(\214le in [A-Z]f*)-.25 E(do)157 684.6 Q
+(echo \255n " <panic: $xf)193 696.6 Q(\214le>" > /de)-.25 E(v/console)-.25 E
+(done)157 708.6 Q EP
+%%Page: 12 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-12 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF .756
+(If you are not running a v)142 96 R .755(ersion of UNIX that supports Berk)
+-.15 F(ele)-.1 E 3.255(yT)-.15 G(CP/IP)416.725 96 Q 3.255(,d)-1.11 G 3.255(on)
+450.27 96 S .755(ot include)463.525 96 R(the)117 108 Q F0(\255bd)2.5 E F1
+(\215ag.)2.5 E F0 2.5(1.3.7. /usr/lib/sendmail.hf)102 132 R F1 2.078
+(This is the help \214le used by the SMTP)142 148.2 R F0(HELP)4.578 E F1 4.578
+(command. It)4.578 F 2.078(should be copied from)4.578 F
+(\231lib/sendmail.hf\232:)117 160.2 Q(cp lib/sendmail.hf /usr/lib)157 176.4 Q
+(The actual path of this \214le is de\214ned in the)117 192.6 Q F0(H)2.5 E F1
+(option of the)2.5 E/F2 10/Times-Italic@0 SF(sendmail.cf)2.5 E F1(\214le.)2.5 E
+F0 2.5(1.3.8. /etc/sendmail.st)102 216.6 R F1 3.04
+(If you wish to collect statistics about your mail traf)142 232.8 R 3.04
+(\214c, you should create the \214le)-.25 F(\231/etc/sendmail.st\232:)117 244.8
+Q(cp /de)157 261 Q(v/null /etc/sendmail.st)-.25 E(chmod 666 /etc/sendmail.st)
+157 273 Q .715(This \214le does not gro)117 289.2 R 4.516 -.65(w. I)-.25 H
+3.216(ti).65 G 3.216(sp)231.502 289.2 S .716
+(rinted with the program \231mailstats/mailstats.c.)243.608 289.2 R 5.716<9a54>
+-.7 G .716(he actual path)447.028 289.2 R(of this \214le is de\214ned in the)
+117 301.2 Q F0(S)2.5 E F1(option of the)2.5 E F2(sendmail.cf)2.5 E F1(\214le.)
+2.5 E F0 2.5(1.3.9. /usr/bin/newaliases)102 325.2 R F1(If)142 341.4 Q F2
+(sendmail)3.256 E F1 .756(is in)3.256 F -.2(vo)-.4 G -.1(ke).2 G 3.256(da).1 G
+3.256<7399>240.424 341.4 S(ne)252.01 341.4 Q -.1(wa)-.25 G(liases,).1 E 3.255
+<9a69>-.7 G 3.255(tw)307.255 341.4 S .755(ill simulate the)320.51 341.4 R F0
+(\255bi)3.255 E F1 .755(\215ag \(i.e., will reb)3.255 F .755(uild the)-.2 F
+(alias database; see belo)117 353.4 Q 2.5(w\). This)-.25 F
+(should be a link to /usr/sbin/sendmail.)2.5 E F0 2.5(1.3.10. /usr/bin/mailq)
+102 377.4 R F1(If)142 393.6 Q F2(sendmail)3.439 E F1 .939(is in)3.439 F -.2(vo)
+-.4 G -.1(ke).2 G 3.439(da).1 G 3.439<7399>241.156 393.6 S(mailq,)252.925 393.6
+Q 3.439<9a69>-.7 G 3.439(tw)288.164 393.6 S .939(ill simulate the)301.603 393.6
+R F0(\255bp)3.439 E F1 .94(\215ag \(i.e.,)3.44 F F2(sendmail)3.44 E F1 .94
+(will print)3.44 F(the contents of the mail queue; see belo)117 405.6 Q 2.5
+(w\). This)-.25 F(should be a link to /usr/sbin/sendmail.)2.5 E F0 2.5
+(2. NORMAL)72 429.6 R(OPERA)2.5 E(TIONS)-.95 E 2.5(2.1. The)87 453.6 R
+(System Log)2.5 E F1 1.511(The system log is supported by the)127 469.8 R F2
+(syslo)4.011 E(gd)-.1 E F1 1.511(\(8\) program.)1.666 F 1.511
+(All messages from)6.511 F F2(sendmail)4.011 E F1(are)4.011 E(logged under the)
+102 481.8 Q/F3 9/Times-Roman@0 SF(LOG_MAIL)2.5 E F1 -.1(fa)2.5 G(cility).1 E(.)
+-.65 E F0 2.5(2.1.1. F)102 505.8 R(ormat)-.25 E F1 .574(Each line in the syste\
+m log consists of a timestamp, the name of the machine that gener)142 522 R(-)
+-.2 E .849(ated it \(for logging from se)117 534 R -.15(ve)-.25 G .849
+(ral machines o).15 F -.15(ve)-.15 G 3.349(rt).15 G .848(he local area netw)
+316.942 534 R .848(ork\), the w)-.1 F .848(ord \231sendmail:\232,)-.1 F
+(and a message.)117 546 Q F0 2.5(2.1.2. Le)102 570 R -.1(ve)-.15 G(ls).1 E F1
+.204(If you ha)142 586.2 R -.15(ve)-.2 G F2(syslo)2.854 E(gd)-.1 E F1 .204
+(\(8\) or an equi)1.666 F -.25(va)-.25 G .205
+(lent installed, you will be able to do logging.).25 F .205(There is)5.205 F
+2.788(al)117 598.2 S(ar)127.008 598.2 Q .287
+(ge amount of information that can be logged.)-.18 F .287
+(The log is arranged as a succession of le)5.287 F -.15(ve)-.25 G(ls.).15 E .65
+(At the lo)117 610.2 R .65(west le)-.25 F -.15(ve)-.25 G 3.15(lo).15 G .65
+(nly e)201.72 610.2 R .651(xtremely strange situations are logged.)-.15 F .651
+(At the highest le)5.651 F -.15(ve)-.25 G .651(l, e).15 F -.15(ve)-.25 G 3.151
+(nt).15 G(he)494.56 610.2 Q .826(most mundane and uninteresting e)117 622.2 R
+-.15(ve)-.25 G .825(nts are recorded for posterity).15 F 5.825(.A)-.65 G 3.325
+(sac)400.27 622.2 S(on)419.69 622.2 Q -.15(ve)-.4 G .825(ntion, log le).15 F
+-.15(ve)-.25 G(ls).15 E .2
+(under ten are considered generally \231useful;\232 log le)117 634.2 R -.15(ve)
+-.25 G .201(ls abo).15 F .501 -.15(ve 6)-.15 H 2.701(4a).15 G .201(re reserv)
+381.566 634.2 R .201(ed for deb)-.15 F .201(ugging pur)-.2 F(-)-.2 E 2.5
+(poses. Le)117 646.2 R -.15(ve)-.25 G(ls from 11\25564 are reserv).15 E
+(ed for v)-.15 E(erbose information that some sites might w)-.15 E(ant.)-.1 E
+2.5(Ac)142 662.4 S(omplete description of the log le)156.16 662.4 Q -.15(ve)
+-.25 G(ls is gi).15 E -.15(ve)-.25 G 2.5(ni).15 G 2.5(ns)340.35 662.4 S
+(ection 4.6.)351.74 662.4 Q F0 2.5(2.2. The)87 686.4 R(Mail Queue)2.5 E F1 .263
+(The mail queue should be processed transparently)127 702.6 R 5.262(.H)-.65 G
+-.25(ow)342.868 702.6 S -2.15 -.25(ev e).25 H 1.062 -.4(r, y).25 H .262
+(ou may \214nd that manual inter).4 F(-)-.2 E -.15(ve)102 714.6 S .081
+(ntion is sometimes necessary).15 F 5.081(.F)-.65 G .081(or e)240.254 714.6 R
+.081(xample, if a major host is do)-.15 F .081
+(wn for a period of time the queue)-.25 F EP
+%%Page: 13 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-13)452.9 60 Q/F1 10/Times-Roman@0 SF .268(may become clogged.)102 96 R
+(Although)5.268 E/F2 10/Times-Italic@0 SF(sendmail)2.768 E F1 .268
+(ought to reco)2.768 F -.15(ve)-.15 G 2.768(rg).15 G .268
+(racefully when the host comes up, you)348.254 96 R
+(may \214nd performance unacceptably bad in the meantime.)102 108 Q F0 2.5
+(2.2.1. Printing)102 132 R(the queue)2.5 E F1 .526
+(The contents of the queue can be printed using the)142 148.2 R F2(mailq)3.026
+E F1 .526(command \(or by specifying the)3.026 F F0(\255bp)117 160.2 Q F1
+(\215ag to)2.5 E F2(sendmail)2.5 E F1(\):)A(mailq)157 176.4 Q 1.673
+(This will produce a listing of the queue id')117 192.6 R 1.673
+(s, the size of the message, the date the message)-.55 F
+(entered the queue, and the sender and recipients.)117 204.6 Q F0 2.5(2.2.2. F)
+102 228.6 R(or)-.25 E(cing the queue)-.18 E F2(Sendmail)142 244.8 Q F1 1.137
+(should run the queue automatically at interv)3.637 F 3.638(als. The)-.25 F
+1.138(algorithm is to read and)3.638 F .355
+(sort the queue, and then to attempt to process all jobs in order)117 256.8 R
+5.355(.W)-.55 G .355(hen it attempts to run the job,)384.37 256.8 R F2
+(sendmail)117 268.8 Q F1(\214rst checks to see if the job is lock)2.5 E 2.5
+(ed. If)-.1 F(so, it ignores the job)2.5 E(.)-.4 E .338
+(There is no attempt to insure that only one queue processor e)142 285 R .338
+(xists at an)-.15 F 2.838(yt)-.15 G .339(ime, since there)440.282 285 R .095
+(is no guarantee that a job cannot tak)117 297 R 2.595(ef)-.1 G(ore)272.07 297
+Q -.15(ve)-.25 G 2.595(rt).15 G 2.595(op)302.585 297 S .094(rocess \(ho)315.18
+297 R(we)-.25 E -.15(ve)-.25 G -.4(r,).15 G F2(sendmail)2.994 E F1 .094
+(does include heuris-)2.594 F 1.086
+(tics to try to abort jobs that are taking absurd amounts of time; technically)
+117 309 R 3.587(,t)-.65 G 1.087(his violates RFC)435.146 309 R .462(821, b)117
+321 R .461(ut is blessed by RFC 1123\).)-.2 F .461
+(Due to the locking algorithm, it is impossible for one job to)5.461 F 1.086
+(freeze the entire queue.)117 333 R(Ho)6.086 E(we)-.25 E -.15(ve)-.25 G 1.886
+-.4(r, a).15 H 3.586(nu).4 G(ncooperati)279.346 333 Q 1.386 -.15(ve r)-.25 H
+1.086(ecipient host or a program recipient that).15 F(ne)117 345 Q -.15(ve)-.25
+G 3.351(rr).15 G .851(eturns can accumulate man)145.491 345 R 3.351(yp)-.15 G
+.851(rocesses in your system.)269.825 345 R(Unfortunately)5.851 E 3.351(,t)-.65
+G .85(here is no com-)439.52 345 R(pletely general w)117 357 Q(ay to solv)-.1 E
+2.5(et)-.15 G(his.)234.23 357 Q .082
+(In some cases, you may \214nd that a major host going do)142 373.2 R .083
+(wn for a couple of days may create)-.25 F 2.925(ap)117 385.2 S(rohibiti)
+129.365 385.2 Q -.15(ve)-.25 G .425(ly lar).15 F .425(ge queue.)-.18 F .424
+(This will result in)5.425 F F2(sendmail)2.924 E F1 .424
+(spending an inordinate amount of time)2.924 F 1.084(sorting the queue.)117
+397.2 R 1.084(This situation can be \214x)6.084 F 1.084(ed by mo)-.15 F 1.085
+(ving the queue to a temporary place and)-.15 F .023(creating a ne)117 409.2 R
+2.523(wq)-.25 G 2.523(ueue. The)182.629 409.2 R .022
+(old queue can be run later when the of)2.523 F .022
+(fending host returns to service.)-.25 F 1.6 -.8(To d)142 425.4 T 2.5(ot).8 G
+(his, it is acceptable to mo)170.09 425.4 Q .3 -.15(ve t)-.15 H
+(he entire queue directory:).15 E(cd /v)157 441.6 Q(ar/spool)-.25 E
+(mv mqueue omqueue; mkdir mqueue; chmod 700 mqueue)157 453.6 Q -1.1(Yo)117
+469.8 S 2.708(us)1.1 G .208(hould then kill the e)139.718 469.8 R .209
+(xisting daemon \(since it will still be processing in the old queue direc-)
+-.15 F(tory\) and create a ne)117 481.8 Q 2.5(wd)-.25 G(aemon.)213.1 481.8 Q
+1.6 -.8(To r)142 498 T(un the old mail queue, run the follo).8 E(wing command:)
+-.25 E(/usr/sbin/sendmail \255oQ/v)157 514.2 Q(ar/spool/omqueue \255q)-.25 E
+(The)117 530.4 Q F0(\255oQ)2.868 E F1 .367
+(\215ag speci\214es an alternate queue directory and the)2.868 F F0<ad71>2.867
+E F1 .367(\215ag says to just run e)2.867 F -.15(ve)-.25 G .367(ry job in).15 F
+.593(the queue.)117 542.4 R .593(If you ha)5.593 F .893 -.15(ve a t)-.2 H
+(endenc).15 E 3.093(yt)-.15 G -2.1 -.25(ow a)263.111 542.4 T .593(rd v).25 F
+-.1(oy)-.2 G .593(eurism, you can use the).1 F F0<ad76>3.094 E F1 .594
+(\215ag to w)3.094 F .594(atch what is)-.1 F(going on.)117 554.4 Q
+(When the queue is \214nally emptied, you can remo)142 570.6 Q .3 -.15(ve t)
+-.15 H(he directory:).15 E(rmdir /v)157 586.8 Q(ar/spool/omqueue)-.25 E F0 2.5
+(2.3. The)87 615 R(Alias Database)2.5 E F1 .361(The alias database e)127 631.2
+R .361(xists in tw)-.15 F 2.861(of)-.1 G 2.861(orms. One)261.116 631.2 R .361
+(is a te)2.861 F .36(xt form, maintained in the \214le)-.15 F F2(/etc/aliases.)
+2.86 E F1(The aliases are of the form)102 643.2 Q(name: name1, name2, ...)142
+659.4 Q(Only local names may be aliased; e.g.,)102 675.6 Q(eric@prep.ai.MIT)142
+691.8 Q(.EDU: eric@CS.Berk)-.74 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E .348
+(will not ha)102 708 R .648 -.15(ve t)-.2 H .348(he desired ef).15 F 2.849
+(fect. Aliases)-.25 F .349(may be continued by starting an)2.849 F 2.849(yc)
+-.15 G .349(ontinuation lines with a)408.783 708 R(space or a tab)102 720 Q 5
+(.B)-.4 G(lank lines and lines be)170.47 720 Q
+(ginning with a sharp sign \(\231#\232\) are comments.)-.15 E EP
+%%Page: 14 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-14 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 1.593
+(The second form is processed by the)127 96 R/F2 10/Times-Italic@0 SF(dbm)4.093
+E F1 1.593(\(3\) \(or)1.666 F F2(db)4.093 E F1 1.593(\(3\)\) library)1.666 F
+6.593(.T)-.65 G 1.593(his form is in the \214les)409.085 96 R F2
+(/etc/aliases.dir)102 108 Q F1(and)3.028 E F2(/etc/aliases.pa)3.028 E -.15(g.)
+-.1 G F1 .528(This is the form that)5.678 F F2(sendmail)3.029 E F1 .529
+(actually uses to resolv)3.029 F 3.029(ea)-.15 G(liases.)479.28 108 Q
+(This technique is used to impro)102 120 Q .3 -.15(ve p)-.15 H(erformance.).15
+E -1.1(Yo)127 136.2 S 2.5(uc)1.1 G(an also use)150.06 136.2 Q/F3 9
+/Times-Roman@0 SF(NIS)2.5 E F1(-based alias \214les.)A -.15(Fo)5 G 2.5(re).15 G
+(xample, the speci\214cation:)305.069 136.2 Q -.35(OA)142 152.4 S(/etc/aliases)
+.35 E -.35(OA)142 164.4 S(nis:mail.aliases@my).35 E(.nis.domain)-.65 E 1.725(w\
+ill \214rst search the /etc/aliases \214le and then the map named \231mail.ali\
+ases\232 in \231my)102 180.6 R(.nis.domain\232.)-.65 E -.8(Wa)102 192.6 S .589
+(rning: if you b).8 F .589(uild your o)-.2 F(wn)-.25 E F3(NIS)3.089 E F1 .589
+(-based alias \214les, be sure to pro)B .59(vide the)-.15 F F0<ad6c>3.09 E F1
+.59(\215ag to)3.09 F F2(mak)3.09 E(edbm)-.1 E F1(\(8\))A .159
+(to map upper case letters in the k)102 204.6 R -.15(ey)-.1 G 2.659(st).15 G
+2.659(ol)253.552 204.6 S -.25(ow)263.991 204.6 S .159
+(er case; otherwise, aliases with upper case letters in their).25 F(names w)102
+216.6 Q(on')-.1 E 2.5(tm)-.18 G(atch incoming addresses.)163.38 216.6 Q
+(Additional \215ags can be added after the colon e)127 232.8 Q(xactly lik)-.15
+E 2.5(ea)-.1 G F0(K)A F1(line \212 for e)2.5 E(xample:)-.15 E -.35(OA)142 249 S
+(nis:-N mail.aliases@my).35 E(.nis.domain)-.65 E
+(will search the appropriate NIS map and al)102 265.2 Q -.1(wa)-.1 G
+(ys include null bytes in the k).1 E -.15(ey)-.1 G(.)-.5 E F0 2.5(2.3.1. Reb)
+102 289.2 R(uilding the alias database)-.2 E F1 .542(The DB or DBM v)142 305.4
+R .542(ersion of the database may be reb)-.15 F .542(uilt e)-.2 F .542
+(xplicitly by e)-.15 F -.15(xe)-.15 G .542(cuting the com-).15 F(mand)117 317.4
+Q(ne)157 333.6 Q -.1(wa)-.25 G(liases).1 E(This is equi)117 349.8 Q -.25(va)
+-.25 G(lent to gi).25 E(ving)-.25 E F2(sendmail)2.5 E F1(the)2.5 E F0(\255bi)
+2.5 E F1(\215ag:)2.5 E(/usr/sbin/sendmail \255bi)157 366 Q .26
+(If the \231D\232 option is speci\214ed in the con\214guration,)142 386.4 R F2
+(sendmail)2.759 E F1 .259(will reb)2.759 F .259(uild the alias database)-.2 F
+1.92(automatically if possible when it is out of date.)117 398.4 R(Auto-reb)
+6.921 E 1.921(uild can be dangerous on hea)-.2 F(vily)-.2 E 1.451
+(loaded machines with lar)117 410.4 R 1.451(ge alias \214les; if it might tak)
+-.18 F 3.951(em)-.1 G 1.45(ore than \214v)355.66 410.4 R 3.95(em)-.15 G 1.45
+(inutes to reb)420.13 410.4 R 1.45(uild the)-.2 F
+(database, there is a chance that se)117 422.4 Q -.15(ve)-.25 G
+(ral processes will start the reb).15 E(uild process simultaneously)-.2 E(.)
+-.65 E 1.77(If you ha)142 438.6 R 2.07 -.15(ve m)-.2 H 1.77
+(ultiple aliases databases speci\214ed, the).15 F F0(\255bi)4.27 E F1 1.77
+(\215ag reb)4.27 F 1.77(uilds all the database)-.2 F
+(types it understands \(for e)117 450.6 Q(xample, it can reb)-.15 E
+(uild dbm databases b)-.2 E(ut not nis databases\).)-.2 E F0 2.5(2.3.2. P)102
+474.6 R(otential pr)-.2 E(oblems)-.18 E F1 1.131
+(There are a number of problems that can occur with the alias database.)142
+490.8 R(The)6.13 E 3.63(ya)-.15 G 1.13(ll result)472.59 490.8 R 1.103(from a)
+117 502.8 R F2(sendmail)3.603 E F1 1.103(process accessing the DBM v)3.603 F
+1.103(ersion while it is only partially b)-.15 F 3.604(uilt. This)-.2 F(can)
+3.604 E 1.249(happen under tw)117 514.8 R 3.749(oc)-.1 G 1.248
+(ircumstances: One process accesses the database while another process is)
+199.237 514.8 R(reb)117 526.8 Q .518(uilding it, or the process reb)-.2 F .518
+(uilding the database dies \(due to being killed or a system crash\))-.2 F
+(before completing the reb)117 538.8 Q(uild.)-.2 E .793(Sendmail has tw)142 555
+R 3.293(ot)-.1 G .792(echniques to try to relie)220.669 555 R 1.092 -.15(ve t)
+-.25 H .792(hese problems.).15 F .792(First, it ignores interrupts)5.792 F .045
+(while reb)117 567 R .045(uilding the database; this a)-.2 F -.2(vo)-.2 G .045
+(ids the problem of someone aborting the process lea).2 F .045(ving a)-.2 F
+(partially reb)117 579 Q(uilt database.)-.2 E(Second, at the end of the reb)5 E
+(uild it adds an alias of the form)-.2 E(@: @)157 595.2 Q .336
+(\(which is not normally le)117 611.4 R -.05(ga)-.15 G 2.836(l\). Before).05 F
+F2(sendmail)2.836 E F1 .336(will access the database, it checks to insure that)
+2.836 F(this entry e)117 625.4 Q(xists)-.15 E/F4 7/Times-Roman@0 SF(5)179.63
+621.4 Q F1(.)183.13 625.4 Q F0 2.5(2.3.3. List)102 649.4 R -.1(ow)2.5 G(ners).1
+E F1 .4(If an error occurs on sending to a certain address, say \231)142 665.6
+R F2(x)A F1<9a2c>A F2(sendmail)2.901 E F1 .401(will look for an alias)2.901 F
+.418(of the form \231o)117 677.6 R(wner)-.25 E(-)-.2 E F2(x)A F1 2.918<9a74>C
+2.918(or)212.632 677.6 S(ecei)223.88 677.6 Q .718 -.15(ve t)-.25 H .418
+(he errors.).15 F .417(This is typically useful for a mailing list where the)
+5.418 F .32 LW 76 687.2 72 687.2 DL 80 687.2 76 687.2 DL 84 687.2 80 687.2 DL
+88 687.2 84 687.2 DL 92 687.2 88 687.2 DL 96 687.2 92 687.2 DL 100 687.2 96
+687.2 DL 104 687.2 100 687.2 DL 108 687.2 104 687.2 DL 112 687.2 108 687.2 DL
+116 687.2 112 687.2 DL 120 687.2 116 687.2 DL 124 687.2 120 687.2 DL 128 687.2
+124 687.2 DL 132 687.2 128 687.2 DL 136 687.2 132 687.2 DL 140 687.2 136 687.2
+DL 144 687.2 140 687.2 DL 148 687.2 144 687.2 DL 152 687.2 148 687.2 DL 156
+687.2 152 687.2 DL 160 687.2 156 687.2 DL 164 687.2 160 687.2 DL 168 687.2 164
+687.2 DL 172 687.2 168 687.2 DL 176 687.2 172 687.2 DL 180 687.2 176 687.2 DL
+184 687.2 180 687.2 DL 188 687.2 184 687.2 DL 192 687.2 188 687.2 DL 196 687.2
+192 687.2 DL 200 687.2 196 687.2 DL 204 687.2 200 687.2 DL 208 687.2 204 687.2
+DL 212 687.2 208 687.2 DL 216 687.2 212 687.2 DL/F5 5/Times-Roman@0 SF(5)93.6
+697.6 Q/F6 8/Times-Roman@0 SF(The \231a\232 option is required in the con\214g\
+uration for this action to occur)3.2 I 4(.T)-.44 G
+(his should normally be speci\214ed.)329.18 700.8 Q EP
+%%Page: 15 10
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-15)452.9 60 Q/F1 10/Times-Roman@0 SF 1.116
+(submitter of the list has no control o)117 96 R -.15(ve)-.15 G 3.617(rt).15 G
+1.117(he maintenance of the list itself; in this case the list)288.4 96 R
+(maintainer w)117 108 Q(ould be the o)-.1 E(wner of the list.)-.25 E -.15(Fo)5
+G 2.5(re).15 G(xample:)309.38 108 Q
+(unix-wizards: eric@ucbarpa, wnj@monet, nosuchuser)157 124.2 Q(,)-.4 E
+(sam@matisse)193 136.2 Q -.25(ow)157 148.2 S(ner).25 E
+(-unix-wizards: eric@ucbarpa)-.2 E -.1(wo)117 164.4 S 1.959(uld cause \231eric\
+@ucbarpa\232 to get the error that will occur when someone sends to unix-).1 F
+(wizards due to the inclusion of \231nosuchuser\232 on the list.)117 176.4 Q
+.958(List o)142 192.6 R .958(wners also cause the en)-.25 F -.15(ve)-.4 G .959
+(lope sender address to be modi\214ed.).15 F .959(The contents of the)5.959 F
+-.25(ow)117 204.6 S .429(ner alias are used if the).25 F 2.929(yp)-.15 G .429
+(oint to a single user)236.364 204.6 R 2.928(,o)-.4 G .428
+(therwise the name of the alias itself is used.)326.436 204.6 R -.15(Fo)117
+216.6 S 2.5(rt).15 G(his reason, and to obe)136.02 216.6 Q 2.5(yI)-.15 G
+(nternet con)233.63 216.6 Q -.15(ve)-.4 G(ntions, a typical scheme w).15 E
+(ould be:)-.1 E 18.49(list: some,)157 232.8 R(set, of, addresses)2.5 E 22.28
+(list-request: list-admin-1,)157 244.8 R(list-admin-2, ...)2.5 E -.25(ow)157
+256.8 S(ner).25 E 26.62(-list: list-request)-.2 F F0 2.5(2.4. User)87 285 R
+(Inf)2.5 E(ormation Database)-.25 E F1 1.059(If you ha)127 301.2 R 1.359 -.15
+(ve a ve)-.2 H 1.059(rsion of).15 F/F2 10/Times-Italic@0 SF(sendmail)3.559 E F1
+1.06(with the user information database compiled in, and you)3.559 F(ha)102
+313.2 Q 2.206 -.15(ve s)-.2 H 1.906(peci\214ed one or more databases using the)
+.15 F F0(U)4.406 E F1 1.905(option, the databases will be searched for a)4.406
+F F2(user)102 325.2 Q F1(:maildrop entry)A 5(.I)-.65 G 2.5(ff)191.34 325.2 S
+(ound, the mail will be sent to the speci\214ed address.)200.5 325.2 Q 1.288
+(If the \214rst tok)127 341.4 R 1.288(en passed to user part of the \231local\
+\232 mailer is an at sign, the at sign will be)-.1 F(stripped of)102 353.4 Q
+2.5(fa)-.25 G(nd this step will be skipped.)155.07 353.4 Q F0 2.5(2.5. P)87
+377.4 R(er)-.2 E(-User F)-.37 E(orwarding \(.f)-.25 E(orward Files\))-.25 E F1
+.121(As an alternati)127 393.6 R .421 -.15(ve t)-.25 H 2.621(ot).15 G .121
+(he alias database, an)210.404 393.6 R 2.621(yu)-.15 G .12
+(ser may put a \214le with the name \231.forw)304.878 393.6 R .12
+(ard\232 in his)-.1 F .205(or her home directory)102 405.6 R 5.205(.I)-.65 G
+2.705(ft)199.92 405.6 S .205(his \214le e)208.735 405.6 R(xists,)-.15 E F2
+(sendmail)2.705 E F1 .205
+(redirects mail for that user to the list of addresses)2.705 F .909
+(listed in the .forw)102 417.6 R .908(ard \214le.)-.1 F -.15(Fo)5.908 G 3.408
+(re).15 G .908
+(xample, if the home directory for user \231mckusick\232 has a .forw)233.98
+417.6 R(ard)-.1 E(\214le with contents:)102 429.6 Q(mckusick@ernie)142 445.8 Q
+(kirk@calder)142 457.8 Q(then an)102 474 Q 2.5(ym)-.15 G(ail arri)146.29 474 Q
+(ving for \231mckusick\232 will be redirected to the speci\214ed accounts.)-.25
+E(Actually)127 490.2 Q 3.374(,t)-.65 G .874
+(he con\214guration \214le de\214nes a sequence of \214lenames to check.)
+169.444 490.2 R .875(By def)5.875 F .875(ault, this is)-.1 F .688(the user')102
+502.2 R 3.188(s.)-.55 G(forw)146.426 502.2 Q .688(ard \214le, b)-.1 F .687
+(ut can be de\214ned to be more generally using the)-.2 F F0(J)3.187 E F1 3.187
+(option. If)3.187 F .687(you change)3.187 F .393(this, you will ha)102 514.2 R
+.693 -.15(ve t)-.2 H 2.893(oi).15 G .393
+(nform your user base of the change; .forw)193.064 514.2 R .393
+(ard is pretty well incorporated into)-.1 F(the collecti)102 526.2 Q .3 -.15
+(ve s)-.25 H(ubconscious.).15 E F0 2.5(2.6. Special)87 550.2 R(Header Lines)2.5
+E F1(Se)127 566.4 Q -.15(ve)-.25 G 1.898(ral header lines ha).15 F 2.197 -.15
+(ve s)-.2 H 1.897
+(pecial interpretations de\214ned by the con\214guration \214le.).15 F(Others)
+6.897 E(ha)102 578.4 Q 1.205 -.15(ve i)-.2 H .905(nterpretations b).15 F .905
+(uilt into)-.2 F F2(sendmail)3.405 E F1 .906
+(that cannot be changed without changing the code.)3.405 F(These)5.906 E -.2
+(bu)102 590.4 S(iltins are described here.).2 E F0 2.5(2.6.1. Retur)102 614.4 R
+(n-Receipt-T)-.15 E(o:)-.92 E F1 1.371
+(If this header is sent, a message will be sent to an)142 630.6 R 3.87(ys)-.15
+G 1.37(peci\214ed addresses when the \214nal)366.88 630.6 R(deli)117 642.6 Q
+-.15(ve)-.25 G .367(ry is complete, that is, when successfully deli).15 F -.15
+(ve)-.25 G .368(red to a mailer with the).15 F F0(l)2.868 E F1 .368
+(\215ag \(local deli)2.868 F(v-)-.25 E .024(ery\) set in the mailer descriptor)
+117 656.6 R/F3 7/Times-Roman@0 SF(6)242.37 652.6 Q F1 5.023(.T)245.87 656.6 S
+.023(his header can be disabled with the \231noreceipts\232 pri)259.503 656.6 R
+-.25(va)-.25 G .323 -.15(cy \215).25 H(ag.).15 E .32 LW 76 666.2 72 666.2 DL 80
+666.2 76 666.2 DL 84 666.2 80 666.2 DL 88 666.2 84 666.2 DL 92 666.2 88 666.2
+DL 96 666.2 92 666.2 DL 100 666.2 96 666.2 DL 104 666.2 100 666.2 DL 108 666.2
+104 666.2 DL 112 666.2 108 666.2 DL 116 666.2 112 666.2 DL 120 666.2 116 666.2
+DL 124 666.2 120 666.2 DL 128 666.2 124 666.2 DL 132 666.2 128 666.2 DL 136
+666.2 132 666.2 DL 140 666.2 136 666.2 DL 144 666.2 140 666.2 DL 148 666.2 144
+666.2 DL 152 666.2 148 666.2 DL 156 666.2 152 666.2 DL 160 666.2 156 666.2 DL
+164 666.2 160 666.2 DL 168 666.2 164 666.2 DL 172 666.2 168 666.2 DL 176 666.2
+172 666.2 DL 180 666.2 176 666.2 DL 184 666.2 180 666.2 DL 188 666.2 184 666.2
+DL 192 666.2 188 666.2 DL 196 666.2 192 666.2 DL 200 666.2 196 666.2 DL 204
+666.2 200 666.2 DL 208 666.2 204 666.2 DL 212 666.2 208 666.2 DL 216 666.2 212
+666.2 DL/F4 5/Times-Roman@0 SF(6)93.6 676.6 Q/F5 8/Times-Roman@0 SF .127
+(Some sites disable this header)3.2 J 2.127(,a)-.32 G .127(nd other \(non-)
+199.959 679.8 R/F6 8/Times-Italic@0 SF(sendmail)A F5 2.127(\)s)C .127
+(ystems do not implement it.)282.772 679.8 R .127(Do not assume that a f)4.127
+F .126(ailure to get a re-)-.08 F .317
+(turn receipt means that the mail did not arri)72 689.4 R -.12(ve)-.2 G 4.317
+(.A).12 G .318(lso, do not assume that getting a return receipt means that the\
+ mail has been read; it)232.509 689.4 R
+(just means that the message has been deli)72 699 Q -.12(ve)-.2 G
+(red to the recipient').12 E 2(sm)-.44 G(ailbox.)285.648 699 Q EP
+%%Page: 16 11
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-16 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(2.6.2. Err)102 96 R(ors-T)-.18 E
+(o:)-.92 E/F1 10/Times-Roman@0 SF .22(If errors occur an)142 112.2 R .22
+(ywhere during processing, this header will cause error messages to go to)-.15
+F(the listed addresses.)117 124.2 Q(This is intended for mailing lists.)5 E
+.385(The Errors-T)142 140.4 R .385(o: header w)-.8 F .384
+(as created in the bad old days when UUCP didn')-.1 F 2.884(tu)-.18 G .384
+(nderstand the)450.016 140.4 R .889(distinction between an en)117 152.4 R -.15
+(ve)-.4 G .889(lope and a header; this w).15 F .889(as a hack to pro)-.1 F .89
+(vide what should no)-.15 F 3.39(wb)-.25 G(e)499.56 152.4 Q(passed as the en)
+117 164.4 Q -.15(ve)-.4 G(lope sender address.).15 E(It should go a)5 E -.1(wa)
+-.15 G 3.8 -.65(y. I).1 H 2.5(ti).65 G 2.5(so)365.22 164.4 S(nly used if the)
+376.61 164.4 Q F0(l)2.5 E F1(option is set.)2.5 E F0 2.5(2.6.3. A)102 188.4 R
+(ppar)-.25 E(ently-T)-.18 E(o:)-.92 E F1 .22
+(If a message comes in with no recipients listed in the message \(in a T)142
+204.6 R .22(o:, Cc:, or Bcc: line\))-.8 F(then)117 216.6 Q/F2 10/Times-Italic@0
+SF(sendmail)2.789 E F1 .289(will add an \231)2.789 F(Apparently-T)-.8 E .289
+(o:\232 header line for an)-.8 F 2.789(yr)-.15 G .29(ecipients it is a)378.08
+216.6 R -.1(wa)-.15 G .29(re of.).1 F .29(This is)5.29 F
+(not put in as a standard recipient line to w)117 228.6 Q(arn an)-.1 E 2.5(yr)
+-.15 G(ecipients that the list is not complete.)319.77 228.6 Q
+(At least one recipient line is required under RFC 822.)142 244.8 Q F0 2.5
+(2.7. IDENT)87 268.8 R(Pr)2.5 E(otocol Support)-.18 E F2(Sendmail)127 285 Q F1
+1.835(supports the IDENT protocol as de\214ned in RFC 1413.)4.335 F 1.835
+(Although this enhances)6.835 F .289
+(identi\214cation of the author of an email message by doing a `)102 297 R .29
+(`call back')-.74 F 2.79('t)-.74 G 2.79(ot)396.17 297 S .29
+(he originating system to)406.74 297 R .469(include the o)102 309 R .469(wner \
+of a particular TCP connection in the audit trail it is in no sense perfect; a\
+ deter)-.25 F(-)-.2 E 1.293(mined for)102 321 R 1.294
+(ger can easily spoof the IDENT protocol.)-.18 F 1.294(The follo)6.294 F 1.294
+(wing description is e)-.25 F 1.294(xcerpted from)-.15 F(RFC 1413:)102 333 Q
+2.5(6. Security)127 349.2 R(Considerations)2.5 E .006
+(The information returned by this protocol is at most as trustw)127 365.4 R
+(orth)-.1 E 2.505(ya)-.05 G 2.505(st)400.505 365.4 S .005(he host pro)409.68
+365.4 R .005(viding it OR)-.15 F .273(the or)127 377.4 R -.05(ga)-.18 G .273
+(nization operating the host.).05 F -.15(Fo)5.273 G 2.773(re).15 G .274
+(xample, a PC in an open lab has fe)295.308 377.4 R 2.774(wi)-.25 G 2.774(fa)
+448.612 377.4 S .574 -.15(ny c)459.156 377.4 T(ontrols).15 E .987(on it to pre)
+127 389.4 R -.15(ve)-.25 G .986(nt a user from ha).15 F .986
+(ving this protocol return an)-.2 F 3.486(yi)-.15 G .986
+(denti\214er the user w)378.056 389.4 R 3.486(ants. Lik)-.1 F(e-)-.1 E 1.441(w\
+ise, if the host has been compromised the information returned may be complete\
+ly erro-)127 401.4 R(neous and misleading.)127 413.4 Q .521(The Identi\214cati\
+on Protocol is not intended as an authorization or access control protocol.)127
+429.6 R(At)5.52 E 1.036(best, it pro)127 441.6 R 1.037
+(vides some additional auditing information with respect to TCP connections.)
+-.15 F(At)6.037 E -.1(wo)127 453.6 S(rst, it can pro).1 E
+(vide misleading, incorrect, or maliciously incorrect information.)-.15 E 1.006
+(The use of the information returned by this protocol for other than auditing \
+is strongly dis-)127 469.8 R 2.697(couraged. Speci\214cally)127 481.8 R 2.697
+(,u)-.65 G .197(sing Identi\214cation Protocol information to mak)228.114 481.8
+R 2.697(ea)-.1 G .197(ccess control deci-)429.186 481.8 R .514(sions - either \
+as the primary method \(i.e., no other checks\) or as an adjunct to other meth\
+ods)127 493.8 R(may result in a weak)127 505.8 Q(ening of normal host security)
+-.1 E(.)-.65 E 1.778(An Identi\214cation serv)127 522 R 1.778(er may re)-.15 F
+-.15(ve)-.25 G 1.778
+(al information about users, entities, objects or processes).15 F .337
+(which might normally be considered pri)127 534 R -.25(va)-.25 G 2.836(te. An)
+.25 F .336(Identi\214cation serv)2.836 F .336(er pro)-.15 F .336
+(vides service which)-.15 F .806
+(is a rough analog of the CallerID services pro)127 546 R .806
+(vided by some phone companies and man)-.15 F 3.306(yo)-.15 G(f)500.67 546 Q
+1.398(the same pri)127 558 R -.25(va)-.25 G 1.698 -.15(cy c).25 H 1.398
+(onsiderations and ar).15 F 1.398
+(guments that apply to the CallerID service apply to)-.18 F 3.545
+(Identi\214cation. If)127 570 R 1.045(you w)3.545 F(ouldn')-.1 E 3.545(tr)-.18
+G 1.045(un a "\214nger" serv)260.33 570 R 1.046(er due to pri)-.15 F -.25(va)
+-.25 G 1.346 -.15(cy c).25 H 1.046(onsiderations you may).15 F(not w)127 582 Q
+(ant to run this protocol.)-.1 E F0 2.5(3. ARGUMENTS)72 606 R F1 .018
+(The complete list of ar)112 622.2 R .018(guments to)-.18 F F2(sendmail)2.517 E
+F1 .017(is described in detail in Appendix A.)2.517 F .017(Some important)5.017
+F(ar)87 634.2 Q(guments are described here.)-.18 E F0 2.5(3.1. Queue)87 658.2 R
+(Inter)2.5 E -.1(va)-.1 G(l).1 E F1 .455(The amount of time between forking a \
+process to run through the queue is de\214ned by the)127 674.4 R F0<ad71>2.956
+E F1 2.706(\215ag. If)102 686.4 R .206(you run in mode)2.706 F F0(f)2.706 E F1
+(or)2.706 E F0(a)2.706 E F1 .206(this can be relati)2.706 F -.15(ve)-.25 G .206
+(ly lar).15 F .206(ge, since it will only be rele)-.18 F -.25(va)-.25 G .205
+(nt when a host).25 F .07(that w)102 698.4 R .07(as do)-.1 F .07
+(wn comes back up.)-.25 F .07(If you run in)5.07 F F0(q)2.57 E F1 .07
+(mode it should be relati)2.57 F -.15(ve)-.25 G .07
+(ly short, since it de\214nes the).15 F
+(maximum amount of time that a message may sit in the queue.)102 710.4 Q EP
+%%Page: 17 12
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-17)452.9 60 Q/F1 10/Times-Roman@0 SF 1.336
+(RFC 1123 section 5.3.1.1 says that this v)127 96 R 1.335
+(alue should be at least 30 minutes \(although that)-.25 F(probably doesn')102
+108 Q 2.5(tm)-.18 G(ak)179.59 108 Q 2.5(es)-.1 G(ense if you use `)199.76 108 Q
+(`queue-only')-.74 E 2.5('m)-.74 G(ode\).)329.08 108 Q F0 2.5(3.2. Daemon)87
+132 R(Mode)2.5 E F1 .084(If you allo)127 148.2 R 2.584(wi)-.25 G .084
+(ncoming mail o)181.162 148.2 R -.15(ve)-.15 G 2.585(ra).15 G 2.585(nI)263.605
+148.2 S .085(PC connection, you should ha)274.52 148.2 R .385 -.15(ve a d)-.2 H
+.085(aemon running.).15 F(This)5.085 E .07(should be set by your)102 160.2 R/F2
+10/Times-Italic@0 SF(/etc/r)2.57 E(c)-.37 E F1 .07(\214le using the)2.57 F F0
+(\255bd)2.57 E F1 2.569(\215ag. The)2.57 F F0(\255bd)2.569 E F1 .069
+(\215ag and the)2.569 F F0<ad71>2.569 E F1 .069(\215ag may be combined)2.569 F
+(in one call:)102 172.2 Q(/usr/sbin/sendmail \255bd \255q30m)142 188.4 Q F0 2.5
+(3.3. F)87 216.6 R(or)-.25 E(cing the Queue)-.18 E F1 .04(In some cases you ma\
+y \214nd that the queue has gotten clogged for some reason.)127 232.8 R -1.1
+(Yo)5.04 G 2.54(uc)1.1 G .04(an force)471.48 232.8 R 3.185(aq)102 244.8 S .685
+(ueue run using the)114.625 244.8 R F0<ad71>3.184 E F1 .684(\215ag \(with no v)
+3.184 F 3.184(alue\). It)-.25 F .684(is entertaining to use the)3.184 F F0
+<ad76>3.184 E F1 .684(\215ag \(v)3.184 F .684(erbose\) when)-.15 F
+(this is done to w)102 256.8 Q(atch what happens:)-.1 E
+(/usr/sbin/sendmail \255q \255v)142 273 Q -1.1(Yo)127 293.4 S 4.004(uc)1.1 G
+1.504(an also limit the jobs to those with a particular queue identi\214er)
+151.564 293.4 R 4.004(,s)-.4 G(ender)428.362 293.4 Q 4.004(,o)-.4 G 4.004(rr)
+461.676 293.4 S(ecipient)472.34 293.4 Q .687
+(using one of the queue modi\214ers.)102 305.4 R -.15(Fo)5.687 G 3.187(re).15 G
+.687(xample, \231\255qRberk)265.659 305.4 R(ele)-.1 E .686
+(y\232 restricts the queue run to jobs that)-.15 F(ha)102 317.4 Q .525 -.15
+(ve t)-.2 H .225(he string \231berk).15 F(ele)-.1 E .225(y\232 some)-.15 F .225
+(where in one of the recipient addresses.)-.25 F(Similarly)5.226 E 2.726<2c99>
+-.65 G .226(\255qSstring\232 lim-)441.184 317.4 R(its the run to particular se\
+nders and \231\255qIstring\232 limits it to particular identi\214ers.)102 329.4
+Q F0 2.5(3.4. Deb)87 353.4 R(ugging)-.2 E F1 1.365(There are a f)127 369.6 R
+1.365(airly lar)-.1 F 1.365(ge number of deb)-.18 F 1.365(ug \215ags b)-.2 F
+1.365(uilt into)-.2 F F2(sendmail)3.865 E F1 6.365(.E)C 1.365(ach deb)417.65
+369.6 R 1.365(ug \215ag has a)-.2 F 1.116(number and a le)102 381.6 R -.15(ve)
+-.25 G 1.116(l, where higher le).15 F -.15(ve)-.25 G 1.116
+(ls means to print out more information.).15 F 1.116(The con)6.116 F -.15(ve)
+-.4 G 1.116(ntion is).15 F .294(that le)102 393.6 R -.15(ve)-.25 G .294
+(ls greater than nine are \231absurd,).15 F 2.794<9a69>-.7 G .294(.e., the)
+274.018 393.6 R 2.794(yp)-.15 G .293(rint out so much information that you w)
+313.616 393.6 R(ouldn')-.1 E(t)-.18 E .691(normally w)102 405.6 R .692
+(ant to see them e)-.1 F .692(xcept for deb)-.15 F .692
+(ugging that particular piece of code.)-.2 F(Deb)5.692 E .692
+(ug \215ags are set)-.2 F(using the)102 417.6 Q F0<ad64>2.5 E F1
+(option; the syntax is:)2.5 E(deb)142 433.8 Q(ug-\215ag:)-.2 E F0<ad64>200.13
+433.8 Q F1(deb)2.5 E(ug-list)-.2 E(deb)142 445.8 Q 13.05(ug-list: deb)-.2 F
+(ug-option [ , deb)-.2 E(ug-option ])-.2 E(deb)142 457.8 Q -.28(ug-option: deb)
+-.2 F(ug-range [ . deb)-.2 E(ug-le)-.2 E -.15(ve)-.25 G 2.5(l]).15 G(deb)142
+469.8 Q 3.07(ug-range: inte)-.2 F(ger | inte)-.15 E(ger \255 inte)-.15 E(ger)
+-.15 E(deb)142 481.8 Q(ug-le)-.2 E -.15(ve)-.25 G 6.24(l: inte).15 F(ger)-.15 E
+(where spaces are for reading ease only)102 498 Q 5(.F)-.65 G(or e)268.64 498 Q
+(xample,)-.15 E 34.99(\255d12 Set)142 514.2 R(\215ag 12 to le)2.5 E -.15(ve)
+-.25 G 2.5(l1).15 G 27.49(\255d12.3 Set)142 526.2 R(\215ag 12 to le)2.5 E -.15
+(ve)-.25 G 2.5(l3).15 G 26.66(\255d3-17 Set)142 538.2 R
+(\215ags 3 through 17 to le)2.5 E -.15(ve)-.25 G 2.5(l1).15 G 19.16
+(\255d3-17.4 Set)142 550.2 R(\215ags 3 through 17 to le)2.5 E -.15(ve)-.25 G
+2.5(l4).15 G -.15(Fo)102 566.4 S 4.066(rac).15 G 1.566(omplete list of the a)
+132.752 566.4 R -.25(va)-.2 G 1.565(ilable deb).25 F 1.565
+(ug \215ags you will ha)-.2 F 1.865 -.15(ve t)-.2 H 4.065(ol).15 G 1.565
+(ook at the code \(the)380.9 566.4 R 4.065(ya)-.15 G 1.565(re too)479.385 566.4
+R(dynamic to k)102 578.4 Q(eep this documentation up to date\).)-.1 E F0 2.5
+(3.5. T)87 602.4 R(rying a Differ)-.74 E(ent Con\214guration File)-.18 E F1
+(An alternati)127 618.6 Q .3 -.15(ve c)-.25 H
+(on\214guration \214le can be speci\214ed using the).15 E F0<ad43>2.5 E F1
+(\215ag; for e)2.5 E(xample,)-.15 E(/usr/sbin/sendmail \255Ctest.cf)142 634.8 Q
+.428(uses the con\214guration \214le)102 651 R F2(test.cf)2.928 E F1 .428
+(instead of the def)2.928 F(ault)-.1 E F2(/etc/sendmail.cf)2.928 E(.)-.15 E F1
+.428(If the)5.428 F F0<ad43>2.928 E F1 .429(\215ag has no v)2.928 F(alue)-.25 E
+(it def)102 663 Q(aults to)-.1 E F2(sendmail.cf)2.5 E F1
+(in the current directory)2.5 E(.)-.65 E F0 2.5(3.6. Changing)87 687 R(the V)
+2.5 E(alues of Options)-.92 E F1(Options can be o)127 703.2 Q -.15(ve)-.15 G
+(rridden using the).15 E F0<ad6f>2.5 E F1 2.5(\215ag. F)2.5 F(or e)-.15 E
+(xample,)-.15 E EP
+%%Page: 18 13
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-18 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF
+(/usr/sbin/sendmail \255oT2m)142 96 Q(sets the)102 112.2 Q F0(T)2.5 E F1
+(\(timeout\) option to tw)2.5 E 2.5(om)-.1 G(inutes for this run only)246.63
+112.2 Q(.)-.65 E .182(Some options ha)127 128.4 R .482 -.15(ve s)-.2 H .182
+(ecurity implications.).15 F .182(Sendmail allo)5.182 F .181
+(ws you to set these, b)-.25 F .181(ut refuses to run)-.2 F(as root thereafter)
+102 140.4 Q(.)-.55 E F0 2.5(3.7. Logging)87 164.4 R -.74(Tr)2.5 G(af\214c).74 E
+F1(Man)127 180.6 Q 3.254(yS)-.15 G .754
+(MTP implementations do not fully implement the protocol.)158.994 180.6 R -.15
+(Fo)5.754 G 3.254(re).15 G .755(xample, some per)428.54 180.6 R(-)-.2 E 1.178(\
+sonal computer based SMTPs do not understand continuation lines in reply codes\
+.)102 192.6 R 1.177(These can be)6.178 F -.15(ve)102 204.6 S .13
+(ry hard to trace.).15 F .13(If you suspect such a problem, you can set traf)
+5.13 F .13(\214c logging using the)-.25 F F0<ad58>2.63 E F1 2.63(\215ag. F)2.63
+F(or)-.15 E -.15(ex)102 216.6 S(ample,).15 E
+(/usr/sbin/sendmail \255X /tmp/traf)142 232.8 Q(\214c -bd)-.25 E
+(will log all traf)102 249 Q(\214c in the \214le)-.25 E/F2 10/Times-Italic@0 SF
+(/tmp/tr)2.5 E(af)-.15 E<8c63>-.18 E F1(.)A .128(This logs a lot of data v)127
+265.2 R .128(ery quickly and should ne)-.15 F -.15(ve)-.25 G 2.628(rb).15 G
+2.628(eu)345.89 265.2 S .128(sed during normal operations.)357.958 265.2 R
+(After)5.128 E 1.326(starting up such a daemon, force the errant implementatio\
+n to send a message to your host.)102 277.2 R(All)6.327 E .505(message traf)102
+289.2 R .505(\214c in and out of)-.25 F F2(sendmail)3.005 E F1 3.004(,i)C .504
+(ncluding the incoming SMTP traf)265.264 289.2 R .504
+(\214c, will be logged in this)-.25 F(\214le.)102 301.2 Q F0 2.5(3.8. Dumping)
+87 325.2 R(State)2.5 E F1 -1.1(Yo)127 341.4 S 2.563(uc)1.1 G .063(an ask)
+150.123 341.4 R F2(sendmail)2.563 E F1 .064
+(to log a dump of the open \214les and the connection cache by sending it a)
+2.563 F/F3 9/Times-Roman@0 SF(SIGUSR1)102 353.4 Q F1 2.5(signal. The)2.5 F
+(results are logged at)2.5 E F3(LOG_DEB)2.5 E(UG)-.09 E F1(priority)2.5 E(.)
+-.65 E F0 2.5(4. TUNING)72 377.4 R F1 1.922
+(There are a number of con\214guration parameters you may w)112 393.6 R 1.922
+(ant to change, depending on the)-.1 F .366(requirements of your site.)87 405.6
+R .367(Most of these are set using an option in the con\214guration \214le.)
+5.366 F -.15(Fo)5.367 G 2.867(re).15 G(xample,)472.06 405.6 Q(the line \231O)87
+417.6 Q(T5d\232 sets option \231T\232 to the v)-.4 E(alue \2315d\232 \(\214v)
+-.25 E 2.5(ed)-.15 G(ays\).)312.55 417.6 Q .735(Most of these options ha)112
+433.8 R 1.035 -.15(ve a)-.2 H .735(ppropriate def).15 F .735
+(aults for most sites.)-.1 F(Ho)5.735 E(we)-.25 E -.15(ve)-.25 G 1.535 -.4
+(r, s).15 H .735(ites ha).4 F .735(ving v)-.2 F .735(ery high)-.15 F .045
+(mail loads may \214nd the)87 445.8 R 2.545(yn)-.15 G .046
+(eed to tune them as appropriate for their mail load.)193.465 445.8 R .046
+(In particular)5.046 F 2.546(,s)-.4 G .046(ites e)459.394 445.8 R(xperi-)-.15 E
+1.088(encing a lar)87 457.8 R 1.088(ge number of small messages, man)-.18 F
+3.588(yo)-.15 G 3.587(fw)294.504 457.8 S 1.087(hich are deli)308.641 457.8 R
+-.15(ve)-.25 G 1.087(red to man).15 F 3.587(yr)-.15 G 1.087
+(ecipients, may \214nd)425.996 457.8 R(that the)87 469.8 Q 2.5(yn)-.15 G
+(eed to adjust the parameters dealing with queue priorities.)129.07 469.8 Q F0
+2.5(4.1. T)87 493.8 R(imeouts)-.18 E F1 .582(All time interv)127 510 R .583
+(als are set using a scaled syntax.)-.25 F -.15(Fo)5.583 G 3.083(re).15 G .583
+(xample, \23110m\232 represents ten minutes,)346.138 510 R
+(whereas \2312h30m\232 represents tw)102 522 Q 2.5(oa)-.1 G(nd a half hours.)
+241.3 522 Q(The full set of scales is:)5 E 16.11(ss)142 538.2 S(econds)165.89
+538.2 Q 12.22(mm)142 550.2 S(inutes)169.78 550.2 Q 15(hh)142 562.2 S(ours)167
+562.2 Q 15(dd)142 574.2 S(ays)167 574.2 Q 12.78(ww)142 586.2 S(eeks)169.22
+586.2 Q F0 2.5(4.1.1. Queue)102 614.4 R(inter)2.5 E -.1(va)-.1 G(l).1 E F1 .18
+(The ar)142 630.6 R .18(gument to the)-.18 F F0<ad71>2.68 E F1 .18
+(\215ag speci\214es ho)2.68 F 2.68(wo)-.25 G .18
+(ften a sub-daemon will run the queue.)319.25 630.6 R .18(This is)5.18 F .967
+(typically set to between \214fteen minutes and one hour)117 642.6 R 5.968(.R)
+-.55 G .968(FC 1123 section 5.3.1.1 recommends)350.968 642.6 R
+(that this be at least 30 minutes.)117 654.6 Q F0 2.5(4.1.2. Read)102 678.6 R
+(timeouts)2.5 E F1 .51(It is possible to time out when reading the standard in\
+put or when reading from a remote)142 694.8 R .324(SMTP serv)117 706.8 R(er)
+-.15 E 5.324(.T)-.55 G .324(hese timeouts are set using the)183.608 706.8 R F0
+(r)2.824 E F1 .324(option in the con\214guration \214le.)2.824 F .324(The ar)
+5.324 F(gument)-.18 E 2.767(is a list of)117 718.8 R F2 -.1(ke)5.266 G(ywor)-.2
+E(d=value)-.37 E F1 5.266(pairs. The)5.266 F 2.766(recognized k)5.266 F -.15
+(ey)-.1 G -.1(wo).15 G 2.766(rds, their def).1 F 2.766(ault v)-.1 F 2.766
+(alues, and the)-.25 F EP
+%%Page: 19 14
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-19)452.9 60 Q/F1 10/Times-Roman@0 SF(minimum v)117 96 Q(alues allo)-.25
+E(wed by RFC 1123 section 5.3.2 are:)-.25 E 46.16(initial The)117 112.2 R -.1
+(wa)2.5 G(it for the initial 220 greeting message [5m, 5m].).1 E 52.28
+(helo The)117 128.4 R -.1(wa)4.226 G 1.727
+(it for a reply from a HELO or EHLO command [5m, unspeci\214ed].).1 F .1
+(This may require a host name lookup, so \214v)189 140.4 R 2.6(em)-.15 G .1
+(inutes is probably a reasonable)380.29 140.4 R(minimum.)189 152.4 Q 46.72
+(mail\207 The)117 168.6 R -.1(wa)2.5 G
+(it for a reply from a MAIL command [10m, 5m].).1 E 48.95(rcpt\207 The)117
+184.8 R -.1(wa)3.481 G .981(it for a reply from a RCPT command [1h, 5m].).1 F
+.982(This should be long)5.982 F
+(because it could be pointing at a list that tak)189 196.8 Q
+(es a long time to e)-.1 E(xpand.)-.15 E 34.5(datainit\207 The)117 213 R -.1
+(wa)2.5 G(it for a reply from a D).1 E -1.21 -1.11(AT A)-.4 H
+(command [5m, 2m].)3.61 E 25.62(datablock\207 The)117 229.2 R -.1(wa)2.696 G
+.196(it for reading a data block \(that is, the body of the message\).).1 F
+.196([1h, 3m].)5.196 F .621
+(This should be long because it also applies to programs piping input to)189
+241.2 R/F2 10/Times-Italic@0 SF(send-)3.121 E(mail)189 253.2 Q F1(which ha)2.5
+E .3 -.15(ve n)-.2 H 2.5(og).15 G(uarantee of promptness.)274.75 253.2 Q 30.06
+(data\214nal\207 The)117 269.4 R -.1(wa)2.806 G .306
+(it for a reply from the dot terminating a message.).1 F .306([1h, 10m].)5.306
+F .306(If this is)5.306 F .883
+(shorter than the time actually needed for the recei)189 281.4 R -.15(ve)-.25 G
+3.384(rt).15 G 3.384(od)412.878 281.4 S(eli)426.262 281.4 Q -.15(ve)-.25 G
+3.384(rt).15 G .884(he message,)454.796 281.4 R(duplicates will be generated.)
+189 293.4 Q(This is discussed in RFC 1047.)5 E 55.06(rset The)117 309.6 R -.1
+(wa)2.5 G(it for a reply from a RSET command [5m, unspeci\214ed].).1 E 53.94
+(quit The)117 325.8 R -.1(wa)2.5 G(it for a reply from a Q).1 E
+(UIT command [2m, unspeci\214ed].)-.1 E 50.61(misc The)117 342 R -.1(wa)2.761 G
+.261(it for a reply from miscellaneous \(b).1 F .261
+(ut short\) commands such as NOOP)-.2 F(\(no-operation\) and VERB \(go into v)
+189 354 Q(erbose mode\).)-.15 E([2m, unspeci\214ed].)5 E 25.06(command\207 In)
+117 370.2 R(serv)2.5 E(er SMTP)-.15 E 2.5(,t)-1.11 G(he time to w)259.4 370.2 Q
+(ait for another command.)-.1 E([1h, 5m].)5 E 49.5(ident The)117 386.4 R
+(timeout w)2.5 E(aiting for a reply to an IDENT query [30s, unspeci\214ed].)-.1
+E -.15(Fo)117 402.6 S 3.633(rc).15 G 1.134
+(ompatibility with old con\214guration \214les, if no `)138.813 402.6 R(`k)-.74
+E -.15(ey)-.1 G -.1(wo).15 G(rd=').1 E 3.634('i)-.74 G 3.634(ss)390.854 402.6 S
+1.134(peci\214ed, all the timeouts)402.268 402.6 R(mark)117 414.6 Q
+(ed with \207 are set to the indicated v)-.1 E(alue.)-.25 E(Man)142 430.8 Q
+2.501(yo)-.15 G 2.501(ft)172.681 430.8 S .001(he RFC 1123 minimum v)181.292
+430.8 R .001(alues may well be too short.)-.25 F F2(Sendmail)5 E F1 -.1(wa)2.5
+G 2.5(sd).1 G(esigned to)463.17 430.8 Q .066
+(the RFC 822 protocols, which did not specify read timeouts; hence,)117 442.8 R
+F2(sendmail)2.567 E F1 .067(does not guarantee)2.567 F .438
+(to reply to messages promptly)117 454.8 R 5.438(.I)-.65 G 2.938(np)249.92
+454.8 S(articular)262.858 454.8 Q 2.938(,a\231)-.4 G .438
+(RCPT\232 command specifying a mailing list will)313.034 454.8 R -.15(ex)117
+468.8 S .205(pand and v).15 F .205(erify the entire list; a lar)-.15 F .205
+(ge list on a slo)-.18 F 2.705(ws)-.25 G .205(ystem may tak)339.81 468.8 R
+2.705(em)-.1 G .205(ore than \214v)413.375 468.8 R 2.705(em)-.15 G(inutes)
+474.11 468.8 Q/F3 7/Times-Roman@0 SF(7)498 464.8 Q F1(.)501.5 468.8 Q 3.036(Ir)
+117 480.8 S .536(ecommend a one hour timeout \212 since this f)126.696 480.8 R
+.536(ailure is rare, a long timeout is not onerous and)-.1 F
+(may ultimately help reduce netw)117 492.8 Q(ork load.)-.1 E -.15(Fo)142 509 S
+2.5(re).15 G(xample, the line:)162.53 509 Q(Orcommand=25m,datablock=3h)157
+525.2 Q .344(sets the serv)117 541.4 R .344(er SMTP command timeout to 25 minu\
+tes and the input data block timeout to three)-.15 F(hours.)117 553.4 Q F0 2.5
+(4.1.3. Message)102 577.4 R(timeouts)2.5 E F1 .237
+(After sitting in the queue for a fe)142 593.6 R 2.737(wd)-.25 G .237
+(ays, a message will time out.)289.726 593.6 R .238(This is to insure that at)
+5.238 F .283(least the sender is a)117 605.6 R -.1(wa)-.15 G .282
+(re of the inability to send a message.).1 F .282
+(The timeout is typically set to three)5.282 F 2.5(days. This)117 617.6 R
+(timeout is set using the)2.5 E F0(T)2.5 E F1
+(option in the con\214guration \214le.)2.5 E .413(The time of submission is se\
+t in the queue, rather than the amount of time left until time-)142 633.8 R
+3.263(out. As)117 645.8 R 3.263(ar)3.263 G .763
+(esult, you can \215ush messages that ha)163.449 645.8 R 1.062 -.15(ve b)-.2 H
+.762(een hanging for a short period by running).15 F
+(the queue with a short message timeout.)117 657.8 Q -.15(Fo)5 G 2.5(re).15 G
+(xample,)302.79 657.8 Q .32 LW 76 669.2 72 669.2 DL 80 669.2 76 669.2 DL 84
+669.2 80 669.2 DL 88 669.2 84 669.2 DL 92 669.2 88 669.2 DL 96 669.2 92 669.2
+DL 100 669.2 96 669.2 DL 104 669.2 100 669.2 DL 108 669.2 104 669.2 DL 112
+669.2 108 669.2 DL 116 669.2 112 669.2 DL 120 669.2 116 669.2 DL 124 669.2 120
+669.2 DL 128 669.2 124 669.2 DL 132 669.2 128 669.2 DL 136 669.2 132 669.2 DL
+140 669.2 136 669.2 DL 144 669.2 140 669.2 DL 148 669.2 144 669.2 DL 152 669.2
+148 669.2 DL 156 669.2 152 669.2 DL 160 669.2 156 669.2 DL 164 669.2 160 669.2
+DL 168 669.2 164 669.2 DL 172 669.2 168 669.2 DL 176 669.2 172 669.2 DL 180
+669.2 176 669.2 DL 184 669.2 180 669.2 DL 188 669.2 184 669.2 DL 192 669.2 188
+669.2 DL 196 669.2 192 669.2 DL 200 669.2 196 669.2 DL 204 669.2 200 669.2 DL
+208 669.2 204 669.2 DL 212 669.2 208 669.2 DL 216 669.2 212 669.2 DL/F4 5
+/Times-Roman@0 SF(7)93.6 679.6 Q/F5 8/Times-Roman@0 SF .344(This v)3.2 J .344
+(eri\214cation includes looking up e)-.12 F -.12(ve)-.2 G .344
+(ry address with the name serv).12 F .344(er; this in)-.12 F -.16(vo)-.32 G(lv)
+.16 E .344(es netw)-.12 F .343(ork delays, and can in some cases)-.08 F
+(can be considerable.)72 692.4 Q EP
+%%Page: 20 15
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-20 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF
+(/usr/sbin/sendmail \255oT1d \255q)157 96 Q(will run the queue and \215ush an)
+117 112.2 Q(ything that is one day old.)-.15 E 1.077
+(Since this option is global, and since you can not)142 128.4 R/F2 10
+/Times-Italic@0 SF 3.577(ap)3.577 G(riori)364.395 128.4 Q F1(kno)3.577 E 3.577
+(wh)-.25 G 1.577 -.25(ow l)416.859 128.4 T 1.077(ong another host).25 F .476
+(outside your domain will be do)117 140.4 R .475(wn, a \214v)-.25 F 2.975(ed)
+-.15 G .475(ay timeout is recommended.)291.785 140.4 R .475(This allo)5.475 F
+.475(ws a recipient)-.25 F 1.579(to \214x the problem e)117 152.4 R -.15(ve)
+-.25 G 4.079(ni).15 G 4.079(fi)222.545 152.4 S 4.079(to)232.734 152.4 S 1.579
+(ccurs at the be)244.593 152.4 R 1.58(ginning of a long week)-.15 F 4.08
+(end. RFC)-.1 F 1.58(1123 section)4.08 F
+(5.3.1.1 says that this parameter should be `)117 164.4 Q
+(`at least 4\2555 days')-.74 E('.)-.74 E(The)142 180.6 Q F0(T)2.711 E F1 .211
+(option can also tak)2.711 F 2.711(eas)-.1 G .21
+(econd timeout indicating a time after which a w)263.637 180.6 R .21
+(arning mes-)-.1 F(sage should be sent; the tw)117 192.6 Q 2.5(ot)-.1 G
+(imeouts are separated by a slash.)234.67 192.6 Q -.15(Fo)5 G 2.5(re).15 G
+(xample, the v)391.28 192.6 Q(alue)-.25 E(5d/4h)157 208.8 Q .971
+(causes email to f)117 225 R .971(ail after \214v)-.1 F 3.471(ed)-.15 G .971
+(ays, b)245.326 225 R .971(ut a w)-.2 F .971
+(arning message will be sent after four hours.)-.1 F(This)5.972 E
+(should be lar)117 237 Q(ge enough that the message will ha)-.18 E .3 -.15
+(ve b)-.2 H(een tried se).15 E -.15(ve)-.25 G(ral times.).15 E F0 2.5(4.2. F)87
+261 R(orking During Queue Runs)-.25 E F1 .303(By setting the)127 277.2 R F0(Y)
+2.802 E F1(option,)2.802 E F2(sendmail)2.802 E F1 .302
+(will fork before each indi)2.802 F .302(vidual message while running the)-.25
+F 2.513(queue. This)102 289.2 R .013(will pre)2.513 F -.15(ve)-.25 G(nt).15 E
+F2(sendmail)2.513 E F1 .013(from consuming lar)2.513 F .013
+(ge amounts of memory)-.18 F 2.513(,s)-.65 G 2.513(oi)421.993 289.2 S 2.513(tm)
+432.286 289.2 S .014(ay be useful in)445.359 289.2 R .592(memory-poor en)102
+301.2 R 3.092(vironments. Ho)-.4 F(we)-.25 E -.15(ve)-.25 G 1.392 -.4(r, i).15
+H 3.092(ft).4 G(he)275.388 301.2 Q F0(Y)3.092 E F1 .591(option is not set,)
+3.091 F F2(sendmail)3.091 E F1 .591(will k)3.091 F .591(eep track of hosts)-.1
+F(that are do)102 313.2 Q(wn during a queue run, which can impro)-.25 E .3 -.15
+(ve p)-.15 H(erformance dramatically).15 E(.)-.65 E(If the)127 329.4 Q F0(Y)2.5
+E F1(option is set,)2.5 E F2(sendmail)2.5 E F1(can not use connection caching.)
+2.5 E F0 2.5(4.3. Queue)87 353.4 R(Priorities)2.5 E F1(Ev)127 369.6 Q 1.128(er\
+y message is assigned a priority when it is \214rst instantiated, consisting o\
+f the message)-.15 F .003(size \(in bytes\) of)102 381.6 R .002
+(fset by the message class times the \231w)-.25 F .002(ork class f)-.1 F .002
+(actor\232 and the number of recipients)-.1 F .637(times the \231w)102 393.6 R
+.637(ork recipient f)-.1 F(actor)-.1 E 4.537 -.7(.\232 T)-.55 H .638
+(he priority is used to order the queue.).7 F .638(Higher numbers for the)5.638
+F(priority mean that the message will be processed later when running the queu\
+e.)102 405.6 Q .329(The message size is included so that lar)127 421.8 R .328
+(ge messages are penalized relati)-.18 F .628 -.15(ve t)-.25 H 2.828(os).15 G
+.328(mall messages.)443.122 421.8 R .285(The message class allo)102 433.8 R
+.285(ws users to send \231high priority\232 messages by including a \231Preced\
+ence:\232 \214eld)-.25 F .008(in their message; the v)102 445.8 R .008
+(alue of this \214eld is look)-.25 F .007(ed up in the)-.1 F F0(P)2.507 E F1
+.007(lines of the con\214guration \214le.)2.507 F .007(Since the)5.007 F 1.966
+(number of recipients af)102 457.8 R 1.967
+(fects the amount of load a message presents to the system, this is also)-.25 F
+(included into the priority)102 469.8 Q(.)-.65 E .895
+(The recipient and class f)127 486 R .895
+(actors can be set in the con\214guration \214le using the)-.1 F F0(y)3.394 E
+F1(and)3.394 E F0(z)3.394 E F1(options)3.394 E(respecti)102 498 Q -.15(ve)-.25
+G(ly).15 E 5.962(.T)-.65 G(he)163.842 498 Q 3.462(yd)-.15 G(ef)186.594 498 Q
+.962(ault to 30000 \(for the recipient f)-.1 F .963
+(actor\) and 1800 \(for the class f)-.1 F 3.463(actor\). The)-.1 F
+(initial priority is:)102 510 Q F2(pri)223.76 528 Q/F3 10/Symbol SF(=)3.16 E F2
+(msgsize)3.18 E F3(-)2.38 E F1(\()2.2 E F2(class).2 E F3<b4>2.47 E F0(z\))2.2 E
+F3(+)2.2 E F1(\()2.2 E F2(nrcpt).36 E F3<b4>2.88 E F0(y\))2.2 E F1(\(Remember)
+102 546 Q 3.328(,h)-.4 G .828(igher v)159.638 546 R .828
+(alues for this parameter actually mean that the job will be treated with lo)
+-.25 F(wer)-.25 E(priority)102 558 Q(.\))-.65 E 1.519(The priority of a job ca\
+n also be adjusted each time it is processed \(that is, each time an)127 574.2
+R .256(attempt is made to deli)102 586.2 R -.15(ve)-.25 G 2.756(ri).15 G .256
+(t\) using the \231w)212.04 586.2 R .256(ork time f)-.1 F(actor)-.1 E 1.656 -.7
+(,\232 s)-.4 H .256(et by the).7 F F0(Z)2.756 E F1 2.756(option. This)2.756 F
+.256(is added to the)2.756 F(priority)102 598.2 Q 2.702(,s)-.65 G 2.703(oi)
+140.442 598.2 S 2.703(tn)150.925 598.2 S .203
+(ormally decreases the precedence of the job, on the grounds that jobs that ha)
+161.408 598.2 R .503 -.15(ve f)-.2 H(ailed).05 E(man)102 610.2 Q 2.5(yt)-.15 G
+(imes will tend to f)129.35 610.2 Q(ail ag)-.1 E(ain in the future.)-.05 E(The)
+5 E F0(Z)2.5 E F1(option def)2.5 E(aults to 90000.)-.1 E F0 2.5(4.4. Load)87
+634.2 R(Limiting)2.5 E F2(Sendmail)127 650.4 Q F1 .102(can be ask)2.602 F .101
+(ed to queue \(b)-.1 F .101(ut not deli)-.2 F -.15(ve)-.25 G .101
+(r\) mail if the system load a).15 F -.15(ve)-.2 G .101(rage gets too high).15
+F .626(using the)102 662.4 R F0(x)3.126 E F1 3.126(option. When)3.126 F .626
+(the load a)3.126 F -.15(ve)-.2 G .626(rage e).15 F .626(xceeds the v)-.15 F
+.626(alue of the)-.25 F F0(x)3.126 E F1 .626(option, the deli)3.126 F -.15(ve)
+-.25 G .627(ry mode is).15 F .987(set to)102 674.4 R F0(q)3.487 E F1 .987
+(\(queue only\) if the)3.487 F F2 .987(Queue F)3.487 F(actor)-.75 E F1(\()3.487
+E F0(q)A F1 .987(option\) di)3.487 F .986(vided by the dif)-.25 F .986
+(ference in the current load)-.25 F -2.25 -.2(av e)102 686.4 T 1.268
+(rage and the).2 F F0(x)3.769 E F1 1.269(option plus one e)3.769 F 1.269
+(xceeds the priority of the message \212 that is, the message is)-.15 F
+(queued if)102 698.4 Q(f:)-.25 E EP
+%%Page: 21 16
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-21)452.9 60 Q/F1 10/Times-Italic@0 SF(pri)269.76 99.23 Q/F2 10
+/Times-Roman@0 SF(>)3.16 E F0(q)312.48 92.23 Q F1(LA)294.81 106.23 Q/F3 10
+/Symbol SF(-)2.23 E F0(x)2.2 E F3(+)2.2 E .4 LW 336.29 96.63 294.23 96.63 DL F2
+(1)331.29 106.23 Q(The)102 120.73 Q F0(q)3.143 E F2 .643(option def)3.143 F
+.642(aults to 600000, so each point of load a)-.1 F -.15(ve)-.2 G .642
+(rage is w).15 F .642(orth 600000 priority points \(as)-.1 F(described abo)102
+132.73 Q -.15(ve)-.15 G(\).).15 E -.15(Fo)127 148.93 S 2.886(rd).15 G .386
+(rastic cases, the)148.626 148.93 R F0(X)2.887 E F2 .387
+(option de\214nes a load a)2.887 F -.15(ve)-.2 G .387(rage at which).15 F F1
+(sendmail)2.887 E F2 .387(will refuse to accept)2.887 F(netw)102 160.93 Q
+(ork connections.)-.1 E
+(Locally generated mail \(including incoming UUCP mail\) is still accepted.)5 E
+F0 2.5(4.5. Deli)87 184.93 R -.1(ve)-.1 G(ry Mode).1 E F2 .417
+(There are a number of deli)127 201.13 R -.15(ve)-.25 G .416(ry modes that).15
+F F1(sendmail)2.916 E F2 .416
+(can operate in, set by the \231d\232 con\214gura-)2.916 F(tion option.)102
+213.13 Q(These modes specify ho)5 E 2.5(wq)-.25 G(uickly mail will be deli)
+263.96 213.13 Q -.15(ve)-.25 G 2.5(red. Le).15 F -.05(ga)-.15 G 2.5(lm).05 G
+(odes are:)418.9 213.13 Q 17.22(id)142 229.33 S(eli)167 229.33 Q -.15(ve)-.25 G
+2.5(ri).15 G(nteracti)194.65 229.33 Q -.15(ve)-.25 G(ly \(synchronously\)).15 E
+15(bd)142 241.33 S(eli)167 241.33 Q -.15(ve)-.25 G 2.5(ri).15 G 2.5(nb)194.65
+241.33 S(ackground \(asynchronously\))207.15 241.33 Q 15(qq)142 253.33 S
+(ueue only \(don')167 253.33 Q 2.5(td)-.18 G(eli)240.42 253.33 Q -.15(ve)-.25 G
+(r\)).15 E 1.49(There are tradeof)102 269.53 R 3.99(fs. Mode)-.25 F 1.491
+(\231i\232 passes the maximum amount of information to the sender)3.99 F 3.991
+(,b)-.4 G 1.491(ut is)485.559 269.53 R .433(hardly e)102 281.53 R -.15(ve)-.25
+G 2.933(rn).15 G(ecessary)155.226 281.53 Q 5.433(.M)-.65 G .433
+(ode \231q\232 puts the minimum load on your machine, b)205.269 281.53 R .432
+(ut means that deli)-.2 F -.15(ve)-.25 G(ry).15 E .437
+(may be delayed for up to the queue interv)102 293.53 R 2.937(al. Mode)-.25 F
+.437(\231b\232 is probably a good compromise.)2.937 F(Ho)5.437 E(we)-.25 E -.15
+(ve)-.25 G -.4(r,).15 G .033(this mode can cause lar)102 305.53 R .032
+(ge numbers of processes if you ha)-.18 F .332 -.15(ve a m)-.2 H .032
+(ailer that tak).15 F .032(es a long time to deli)-.1 F -.15(ve)-.25 G(r).15 E
+2.5(am)102 317.53 S(essage.)116.72 317.53 Q .337
+(If you run in mode \231q\232 \(queue only\) or \231b\232 \(deli)127 333.73 R
+-.15(ve)-.25 G 2.838(ri).15 G 2.838(nb)341.09 333.73 S(ackground\))353.928
+333.73 Q F1(sendmail)2.838 E F2 .338(will not e)2.838 F(xpand)-.15 E 1.314
+(aliases and follo)102 345.73 R 3.813(w.)-.25 G(forw)182.901 345.73 Q 1.313
+(ard \214les upon initial receipt of the mail.)-.1 F 1.313
+(This speeds up the response to)6.313 F(RCPT commands.)102 357.73 Q F0 2.5
+(4.6. Log)87 381.73 R(Le)2.5 E -.1(ve)-.15 G(l).1 E F2 .189(The le)127 397.93 R
+-.15(ve)-.25 G 2.689(lo).15 G 2.689(fl)171.968 397.93 S .189
+(ogging can be set for)180.767 397.93 R F1(sendmail)2.689 E F2 5.189(.T)C .189
+(he def)317.991 397.93 R .19(ault using a standard con\214guration table)-.1 F
+(is le)102 409.93 Q -.15(ve)-.25 G 2.5(l9).15 G 5(.T)137.71 409.93 S(he le)
+151.32 409.93 Q -.15(ve)-.25 G(ls are as follo).15 E(ws:)-.25 E 31(0N)102
+426.13 S 2.5(ol)145.22 426.13 S(ogging.)155.5 426.13 Q 31(1S)102 442.33 S
+(erious system f)143.56 442.33 Q(ailures and potential security problems.)-.1 E
+31(2L)102 458.53 S(ost communications \(netw)144.11 458.53 Q
+(ork problems\) and protocol f)-.1 E(ailures.)-.1 E 31(3O)102 474.73 S
+(ther serious f)145.22 474.73 Q(ailures.)-.1 E 31(4M)102 490.93 S(inor f)146.89
+490.93 Q(ailures.)-.1 E 31(5M)102 507.13 S(essage collection statistics.)146.89
+507.13 Q 31(6C)102 523.33 S(reation of error messages, VRFY and EXPN commands.)
+144.67 523.33 Q 31(7D)102 539.53 S(eli)145.22 539.53 Q -.15(ve)-.25 G(ry f).15
+E(ailures \(host or user unkno)-.1 E(wn, etc.\).)-.25 E 31(8S)102 555.73 S
+(uccessful deli)143.56 555.73 Q -.15(ve)-.25 G(ries.).15 E 31(9M)102 571.93 S
+(essages being deferred \(due to a host being do)146.89 571.93 Q(wn, etc.\).)
+-.25 E 23.5(10 Database)102 588.13 R -.15(ex)2.5 G(pansion \(alias, forw).15 E
+(ard, and userdb lookups\).)-.1 E 23.5(15 Automatic)102 604.33 R
+(alias database reb)2.5 E(uilds.)-.2 E 23.5(20 Logs)102 620.53 R .603
+(attempts to run lock)3.103 F .603(ed queue \214les.)-.1 F .603
+(These are not errors, b)5.603 F .603(ut can be useful to note if)-.2 F
+(your queue appears to be clogged.)138 632.53 Q 23.5(30 Lost)102 648.73 R
+(locks \(only if using lockf instead of \215ock\).)2.5 E(Additionally)102
+664.93 Q 3.683(,v)-.65 G 1.183(alues abo)162.843 664.93 R 1.483 -.15(ve 6)-.15
+H 3.683(4a).15 G 1.183(re reserv)232.462 664.93 R 1.183(ed for e)-.15 F 1.183
+(xtremely v)-.15 F 1.184(erbose deb)-.15 F 1.184(uggging output.)-.2 F 1.184
+(No normal)6.184 F(site w)102 676.93 Q(ould e)-.1 E -.15(ve)-.25 G 2.5(rs).15 G
+(et these.)168.99 676.93 Q EP
+%%Page: 22 17
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-22 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(4.7. File)87 96 R(Modes)2.5 E/F1 10
+/Times-Roman@0 SF .813(There are a number of \214les that may ha)127 112.2 R
+1.113 -.15(ve a n)-.2 H .813(umber of modes.).15 F .813
+(The modes depend on what)5.813 F(functionality you w)102 124.2 Q
+(ant and the le)-.1 E -.15(ve)-.25 G 2.5(lo).15 G 2.5(fs)253.15 124.2 S
+(ecurity you require.)262.87 124.2 Q F0 2.5(4.7.1. T)102 148.2 R 2.5(os)-.92 G
+(uid or not to suid?)146.64 148.2 Q/F2 10/Times-Italic@0 SF(Sendmail)142 164.4
+Q F1 .933(can safely be made setuid to root.)3.433 F .934
+(At the point where it is about to)5.934 F F2 -.2(ex)3.434 G(ec).2 E F1 .934
+(\(2\) a)1.666 F(mailer)117 176.4 Q 2.583(,i)-.4 G 2.583(tc)150.013 176.4 S
+.082(hecks to see if the userid is zero; if so, it resets the userid and group\
+id to a def)159.816 176.4 R .082(ault \(set)-.1 F .576(by the)117 188.4 R F0(u)
+3.076 E F1(and)3.076 E F0(g)3.076 E F1 3.076(options\). \(This)3.076 F .576
+(can be o)3.076 F -.15(ve)-.15 G .576(rridden by setting the).15 F F0(S)3.076 E
+F1 .577(\215ag to the mailer for mailers)3.077 F 1.532
+(that are trusted and must be called as root.\))117 200.4 R(Ho)6.531 E(we)-.25
+E -.15(ve)-.25 G 2.331 -.4(r, t).15 H 1.531
+(his will cause mail processing to be).4 F(accounted \(using)117 212.4 Q F2(sa)
+2.5 E F1(\(8\)\) to root rather than to the user sending the mail.)1.666 E F0
+2.5(4.7.2. Should)102 236.4 R(my alias database be writable?)2.5 E F1 .058
+(At Berk)142 252.6 R(ele)-.1 E 2.558(yw)-.15 G 2.558(eh)200.186 252.6 S -2.25
+-.2(av e)212.184 252.6 T .058(the alias database \(/etc/aliases*\) mode 644.)
+2.758 F .058(While this is not as \215e)5.058 F(x-)-.15 E 1.719
+(ible as if the database were more 666, it a)117 264.6 R -.2(vo)-.2 G 1.718
+(ids potential security problems with a globally).2 F(writable database.)117
+276.6 Q 1.19(The database that)142 292.8 R F2(sendmail)3.69 E F1 1.191
+(actually used is represented by the tw)3.691 F 3.691<6f8c>-.1 G(les)429.118
+292.8 Q F2(aliases.dir)3.691 E F1(and)3.691 E F2(aliases.pa)117 304.8 Q(g)-.1 E
+F1 .159(\(both in /etc\) \(or)2.659 F F2(aliases.db)2.659 E F1 .159
+(if you are running with the ne)2.659 F 2.658(wB)-.25 G(erk)412.854 304.8 Q
+(ele)-.1 E 2.658(yd)-.15 G .158(atabase prim-)449.692 304.8 R(iti)117 316.8 Q
+-.15(ve)-.25 G 3.606(s\). The).15 F 1.107
+(mode on these \214les should match the mode on /etc/aliases.)3.606 F(If)6.107
+E F2(aliases)3.607 E F1 1.107(is writable)3.607 F 1.624(and the DBM \214les \()
+117 328.8 R F2(aliases.dir)A F1(and)4.124 E F2(aliases.pa)4.124 E(g)-.1 E F1
+4.124(\)a)C 1.624(re not, users will be unable to re\215ect their)324.648 328.8
+R .719(desired changes through to the actual database.)117 340.8 R(Ho)5.719 E
+(we)-.25 E -.15(ve)-.25 G 1.519 -.4(r, i).15 H(f).4 E F2(aliases)3.219 E F1 .72
+(is read-only and the DBM)3.219 F(\214les are writable, a slightly sophisticat\
+ed user can arrange to steal mail an)117 352.8 Q(yw)-.15 E(ay)-.1 E(.)-.65 E
+.621(If your DBM \214les are not writable by the w)142 369 R .62
+(orld or you do not ha)-.1 F .92 -.15(ve a)-.2 H(uto-reb).15 E .62
+(uild enabled)-.2 F .564(\(with the \231D\232 option\), then you must be caref\
+ul to reconstruct the alias database each time you)117 381 R(change the te)117
+393 Q(xt v)-.15 E(ersion:)-.15 E(ne)157 409.2 Q -.1(wa)-.25 G(liases).1 E
+(If this step is ignored or for)117 425.4 Q(gotten an)-.18 E 2.5(yi)-.15 G
+(ntended changes will also be ignored or for)273.32 425.4 Q(gotten.)-.18 E F0
+2.5(4.8. Connection)87 449.4 R(Caching)2.5 E F1 .642
+(When processing the queue,)127 465.6 R F2(sendmail)3.142 E F1 .642
+(will try to k)3.142 F .642(eep the last fe)-.1 F 3.142(wo)-.25 G .642
+(pen connections open to)405.144 465.6 R -.2(avo)102 477.6 S
+(id startup and shutdo).2 E(wn costs.)-.25 E
+(This only applies to IPC connections.)5 E .286
+(When trying to open a connection the cache is \214rst searched.)127 493.8 R
+.287(If an open connection is found,)5.286 F .92
+(it is probed to see if it is still acti)102 505.8 R 1.22 -.15(ve b)-.25 H 3.42
+(ys).15 G .92(ending a)270.892 505.8 R/F3 9/Times-Roman@0 SF(NOOP)3.42 E F1
+3.42(command. It)3.42 F .92(is not an error if this f)3.42 F(ails;)-.1 E
+(instead, the connection is closed and reopened.)102 517.8 Q -1 -.8(Tw o)127
+534 T .207(parameters control the connection cache.)3.506 F(The)5.207 E F0(k)
+2.707 E F1 .207(option de\214nes the number of simultane-)2.707 F 1.82
+(ous open connections that will be permitted.)102 546 R 1.819
+(If it is set to zero, connections will be closed as)6.82 F .795
+(quickly as possible.)102 558 R .796(The def)5.796 F .796(ault is one.)-.1 F
+.796(This should be set as appropriate for your system size; it)5.796 F
+(will limit the amount of system resources that)102 570 Q F2(sendmail)2.5 E F1
+(will use during queue runs.)2.5 E(The)127 586.2 Q F0(K)3.648 E F1 1.148
+(option speci\214es the maximum time that an)3.648 F 3.648(yc)-.15 G 1.148
+(ached connection will be permitted to)347.452 586.2 R 2.895(idle. When)102
+598.2 R .395(the idle time e)2.895 F .395(xceeds this v)-.15 F .396
+(alue the connection is closed.)-.25 F .396(This number should be small)5.396 F
+.163(\(under ten minutes\) to pre)102 610.2 R -.15(ve)-.25 G .163
+(nt you from grabbing too man).15 F 2.663(yr)-.15 G .162
+(esources from other hosts.)347.49 610.2 R .162(The def)5.162 F(ault)-.1 E
+(is \214v)102 622.2 Q 2.5(em)-.15 G(inutes.)136.3 622.2 Q F0 2.5(4.9. Name)87
+646.2 R(Ser)2.5 E -.1(ve)-.1 G 2.5(rA).1 G(ccess)172.33 646.2 Q F1 .421
+(If your system supports the name serv)127 662.4 R(er)-.15 E 2.921(,t)-.4 G
+.421(hen the probability is that)297.147 662.4 R F2(sendmail)2.921 E F1 .422
+(will be using it)2.922 F(re)102 674.4 Q -.05(ga)-.15 G 1.432(rdless of ho).05
+F 3.932(wy)-.25 G 1.432(ou con\214gure)184.436 674.4 R F2(sendmail)3.932 E F1
+6.432(.I)C 3.932(np)288.442 674.4 S(articular)302.374 674.4 Q 3.932(,t)-.4 G
+1.431(he system routine)344.506 674.4 R F2 -.1(ge)3.931 G(thostbyname).1 E F1
+1.431(\(3\) is)B .43(used to look up host names, and most v)102 686.4 R .431
+(endor v)-.15 F .431(ersions try some combination of DNS, NIS, and \214le)-.15
+F(lookup in /etc/hosts.)102 698.4 Q EP
+%%Page: 23 18
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-23)452.9 60 Q/F1 10/Times-Roman@0 SF(Ho)127 96 Q(we)-.25 E -.15(ve)-.25
+G 2.12 -.4(r, i).15 H 3.82(fy).4 G 1.32(ou do not ha)183.85 96 R 1.62 -.15
+(ve a n)-.2 H(ameserv).15 E 1.32
+(er con\214gured at all, such as at a UUCP-only site,)-.15 F/F2 10
+/Times-Italic@0 SF(sendmail)102 108 Q F1 .14(will get a \231connection refused\
+\232 message when it tries to connect to the name serv)2.64 F .14(er \(either)
+-.15 F .915(indirectly by calling)102 120 R F2 -.1(ge)3.415 G(thostbyname).1 E
+F1 .915(or directly by looking up MX records\).)3.415 F .915(If the)5.915 F F0
+(I)3.415 E F1 .915(option is set,)3.415 F F2(sendmail)102 132 Q F1 .135
+(will interpret this to mean a temporary f)2.635 F .135
+(ailure and will queue the mail for later processing;)-.1 F .884
+(otherwise, it ignores the name serv)102 144 R .884(er data.)-.15 F .884
+(If your name serv)5.884 F .884(er is running properly)-.15 F 3.383(,t)-.65 G
+.883(he setting of)452.794 144 R 1.164(this option is not rele)102 156 R -.25
+(va)-.25 G 1.164(nt; ho).25 F(we)-.25 E -.15(ve)-.25 G 1.964 -.4(r, i).15 H
+3.664(ti).4 G 3.664(si)265.818 156 S 1.164
+(mportant that it be set properly to mak)276.152 156 R 3.665(ee)-.1 G 1.165
+(rror handling)450.345 156 R -.1(wo)102 168 S(rk properly).1 E(.)-.65 E .633
+(This option also allo)127 184.2 R .633(ws you to tweak name serv)-.25 F .633
+(er options.)-.15 F .632(The command line tak)5.633 F .632(es a series)-.1 F
+.442(of \215ags as documented in)102 196.2 R F2 -.37(re)2.942 G(solver).37 E F1
+.442(\(3\) \(with the leading \231RES_\232 deleted\).)B .442
+(Each can be preceded by)5.442 F(an optional `+' or `)102 208.2 Q/F3 10/Symbol
+SF(-)A F1 2.5('. F)B(or e)-.15 E(xample, the line)-.15 E(OIT)142 224.4 Q
+(rue +AA)-.35 E(ONL)-.55 E(Y)-1 E F3(-)2.5 E F1(DNSRCH)A .862(turns on the AA)
+102 240.6 R(ONL)-.55 E 3.362(Y\()-1 G .862(accept authoritati)201.658 240.6 R
+1.162 -.15(ve a)-.25 H .861(nswers only\) and turns of).15 F 3.361(ft)-.25 G
+.861(he DNSRCH \(search the)402.827 240.6 R 2.039(domain path\) options.)102
+252.6 R 2.039(Most resolv)7.039 F 2.039(er libraries def)-.15 F 2.039
+(ault DNSRCH, DEFN)-.1 F 2.039(AMES, and RECURSE)-.35 F .187
+(\215ags on and all others of)102 264.6 R 2.687(f. Note)-.25 F .186
+(the use of the initial `)2.686 F(`T)-.74 E(rue')-.35 E 2.686('\212t)-.74 G
+.186(his is for compatibility with pre)365.82 264.6 R(vi-)-.25 E(ous v)102
+276.6 Q(ersions of)-.15 E F2(sendmail)2.5 E F1 2.5(,b)C
+(ut is not otherwise necessary)210.81 276.6 Q(.)-.65 E -1.11(Ve)127 292.8 S
+2.256(rsion le)1.11 F -.15(ve)-.25 G 4.756(l1c).15 G 2.256
+(on\214gurations turn DNSRCH and DEFN)200.298 292.8 R 2.257(AMES of)-.35 F
+4.757(fw)-.25 G 2.257(hen doing deli)424.896 292.8 R -.15(ve)-.25 G(ry).15 E
+2.06(lookups, b)102 304.8 R 2.06(ut lea)-.2 F 2.36 -.15(ve t)-.2 H 2.06
+(hem on e).15 F -.15(ve)-.25 G 2.06(rywhere else.).15 F -1.11(Ve)7.06 G 2.06
+(rsion 8 of)1.11 F F2(sendmail)4.56 E F1 2.06(ignores them when doing)4.56 F
+.313(canoni\214cation lookups \(that is, when using $[ ... $]\), and al)102
+316.8 R -.1(wa)-.1 G .313(ys does the search.).1 F .313(If you don')5.313 F
+2.813(tw)-.18 G(ant)491.78 316.8 Q(to do automatic name e)102 328.8 Q
+(xtension, don')-.15 E 2.5(tc)-.18 G(all $[ ... $].)261.93 328.8 Q .189
+(The search rules for $[ ... $] are some)127 345 R .189(what dif)-.25 F .189
+(ferent than usual.)-.25 F .189(If the name \(that is, the `)5.189 F(`...)-.74
+E -.74('')-.7 G(\)).74 E .109(has at least one dot, it al)102 357 R -.1(wa)-.1
+G .109(ys tries the unmodi\214ed name \214rst.).1 F .11(If that f)5.11 F .11
+(ails, it tries the reduced search)-.1 F .124
+(path, and lastly tries the unmodi\214ed name \(b)102 369 R .124
+(ut only for names without a dot, since names with a dot)-.2 F(ha)102 381 Q
+.788 -.15(ve a)-.2 H .488(lready been tried\).).15 F .488(This allo)5.488 F
+.489(ws names such as `)-.25 F(`utc.CS')-.74 E 2.989('t)-.74 G 2.989(om)362.805
+381 S .489(atch the site in Czechoslo)378.574 381 R -.25(va)-.15 G(kia).25 E
+1.588(rather than the site in your local Computer Science department.)102 393 R
+1.587(It also prefers A and CN)6.587 F(AME)-.35 E .512(records o)102 405 R -.15
+(ve)-.15 G 3.012(rM).15 G 3.012(Xr)163.814 405 S .512
+(ecords \212 that is, if it \214nds an MX record it mak)177.376 405 R .513
+(es note of it, b)-.1 F .513(ut k)-.2 F .513(eeps looking.)-.1 F 1.542(This w)
+102 417 R(ay)-.1 E 4.042(,i)-.65 G 4.042(fy)149.054 417 S 1.541(ou ha)161.426
+417 R 1.841 -.15(ve a w)-.2 H 1.541
+(ildcard MX record matching your domain, it will not assume that all).15 F
+(names match.)102 429 Q F0 2.5(4.10. Mo)87 453 R(ving the P)-.1 E(er)-.2 E
+(-User F)-.37 E(orward Files)-.25 E F1 .772(Some sites mount each user')127
+469.2 R 3.272(sh)-.55 G .772(ome directory from a local disk on their w)256.13
+469.2 R .772(orkstation, so that)-.1 F .576(local access is f)102 481.2 R 3.076
+(ast. Ho)-.1 F(we)-.25 E -.15(ve)-.25 G 1.376 -.4(r, t).15 H .575
+(he result is that .forw).4 F .575(ard \214le lookups are slo)-.1 F 4.375 -.65
+(w. I)-.25 H 3.075(ns).65 G .575(ome cases, mail)439.25 481.2 R .216(can e)102
+493.2 R -.15(ve)-.25 G 2.716(nb).15 G 2.716(ed)144.792 493.2 S(eli)156.948
+493.2 Q -.15(ve)-.25 G .216
+(red on machines inappropriately because of a \214le serv).15 F .216
+(er being do)-.15 F 2.716(wn. The)-.25 F(perfor)2.716 E(-)-.2 E
+(mance can be especially bad if you run the automounter)102 505.2 Q(.)-.55 E
+(The)127 521.4 Q F0(J)2.5 E F1(option allo)2.5 E(ws you to set a path of forw)
+-.25 E(ard \214les.)-.1 E -.15(Fo)5 G 2.5(re).15 G
+(xample, the con\214g \214le line)366.6 521.4 Q(OJ/v)142 537.6 Q(ar/forw)-.25 E
+(ard/$u:$z/.forw)-.1 E(ard)-.1 E -.1(wo)102 553.8 S .208
+(uld \214rst look for a \214le with the same name as the user').1 F 2.707(sl)
+-.55 G .207(ogin in /v)343.191 553.8 R(ar/forw)-.25 E .207
+(ard; if that is not found)-.1 F .129
+(\(or is inaccessible\) the \214le \231.forw)102 565.8 R .129
+(ard\232 in the user')-.1 F 2.629(sh)-.55 G .13(ome directory is searched.)
+311.901 565.8 R 2.63(At)5.13 G .13(ruly perv)435.02 565.8 R .13(erse site)-.15
+F(could also search by sender by using $r)102 577.8 Q 2.5(,$)-.4 G(s, or $f.)
+269.07 577.8 Q .69(If you create a directory such as /v)127 594 R(ar/forw)-.25
+E .69(ard, it should be mode 1777 \(that is, the stick)-.1 F 3.19(yb)-.15 G(it)
+498.44 594 Q(should be set\).)102 606 Q
+(Users should create the \214les mode 644.)5 E F0 2.5(4.11. Fr)87 630 R
+(ee Space)-.18 E F1 1.122(On systems that ha)127 646.2 R 1.422 -.15(ve t)-.2 H
+(he).15 E F2(statfs)3.622 E F1 1.123
+(\(2\) system call, you can specify a minimum number of free)B .61
+(blocks on the queue \214lesystem using the)102 658.2 R F0(b)3.11 E F1 3.11
+(option. If)3.11 F .61(there are fe)3.11 F .61
+(wer than the indicated number of)-.25 F .406
+(blocks free on the \214lesystem on which the queue is mounted the SMTP serv)
+102 670.2 R .407(er will reject mail with)-.15 F(the 452 error code.)102 682.2
+Q(This in)5 E(vites the SMTP client to try ag)-.4 E(ain later)-.05 E(.)-.55 E
+(Be)127 698.4 Q -.1(wa)-.25 G .746(re of setting this option too high; it can \
+cause rejection of email when that mail w).1 F(ould)-.1 E
+(be processed without dif)102 710.4 Q(\214culty)-.25 E(.)-.65 E EP
+%%Page: 24 19
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-24 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 1.772
+(This option can also specify an adv)127 96 R 1.773
+(ertised \231maximum message size\232 for hosts that speak)-.15 F(ESMTP)102 108
+Q(.)-1.11 E F0 2.5(4.12. Pri)87 132 R -.1(va)-.1 G(cy Flags).1 E F1(The)127
+148.2 Q F0(p)3.591 E F1 1.091(option allo)3.591 F 1.091
+(ws you to set certain `)-.25 F(`pri)-.74 E -.25(va)-.25 G -.15(cy).25 G 2.571
+-.74('' \215).15 H 3.591(ags. Actually).74 F 3.59(,m)-.65 G(an)409.27 148.2 Q
+3.59(yo)-.15 G 3.59(ft)432.15 148.2 S 1.09(hem don')441.85 148.2 R 3.59(tg)-.18
+G -2.15 -.25(iv e)492.18 148.2 T .254(you an)102 160.2 R 2.754(ye)-.15 G .254
+(xtra pri)141.088 160.2 R -.25(va)-.25 G -.15(cy).25 G 2.754(,r)-.5 G .254
+(ather just insisting that client SMTP serv)196.666 160.2 R .254
+(ers use the HELO command before)-.15 F(using certain commands.)102 172.2 Q
+.124(The option tak)127 188.4 R .124
+(es a series of \215ag names; the \214nal pri)-.1 F -.25(va)-.25 G .424 -.15
+(cy i).25 H 2.624(st).15 G .124(he inclusi)367.708 188.4 R .424 -.15(ve o)-.25
+H 2.624(ro).15 G 2.624(ft)434.06 188.4 S .123(hose \215ags.)442.794 188.4 R
+-.15(Fo)5.123 G(r).15 E -.15(ex)102 200.4 S(ample:).15 E(Op needmailhelo, noe)
+142 216.6 Q(xpn)-.15 E .928(insists that the HELO or EHLO command be used befo\
+re a MAIL command is accepted and dis-)102 232.8 R(ables the EXPN command.)102
+244.8 Q .244(The \231restrictmailq\232 option restricts printing the queue to \
+the group that o)127 261 R .244(wns the queue direc-)-.25 F(tory)102 273 Q 5
+(.I)-.65 G 2.5(ti)128.29 273 S 2.5(sa)136.35 273 S
+(bsurd to set this if you don')147.18 273 Q 2.5(ta)-.18 G
+(lso protect the logs.)266.72 273 Q .83(The \231restrictqrun\232 option restri\
+cts people running the queue \(that is, using the)127 289.2 R F0<ad71>3.33 E F1
+(command)3.33 E(line \215ag\) to root and the o)102 301.2 Q
+(wner of the queue directory)-.25 E(.)-.65 E F0 2.5(4.13. Send)87 325.2 R
+(to Me T)2.5 E(oo)-.92 E F1(Normally)127 341.4 Q(,)-.65 E/F2 10/Times-Italic@0
+SF(sendmail)3.424 E F1 .924(deletes the \(en)3.424 F -.15(ve)-.4 G .923
+(lope\) sender from an).15 F 3.423(yl)-.15 G .923(ist e)375.488 341.4 R 3.423
+(xpansions. F)-.15 F .923(or e)-.15 F .923(xample, if)-.15 F .761(\231matt\232\
+ sends to a list that contains \231matt\232 as one of the members he w)102
+353.4 R(on')-.1 E 3.261(tg)-.18 G .761(et a cop)416.705 353.4 R 3.261(yo)-.1 G
+3.261(ft)462.488 353.4 S .761(he mes-)471.859 353.4 R 3.067(sage. If)102 365.4
+R(the)3.067 E F0<ad6d>3.067 E F1 .567
+(\(me too\) command line \215ag, or if the)3.067 F F0(m)3.066 E F1 .566
+(option is set in the con\214guration \214le, this)3.066 F(beha)102 377.4 Q
+(viour is supressed.)-.2 E(Some sites lik)5 E 2.5(et)-.1 G 2.5(or)265.58 377.4
+S(un the)276.41 377.4 Q/F3 9/Times-Roman@0 SF(SMTP)2.5 E F1(daemon with)2.5 E
+F0<ad6d>2.5 E F1(.)A F0 2.5(5. THE)72 401.4 R(WHOLE SCOOP ON THE CONFIGURA)2.5
+E(TION FILE)-.95 E F1 .264(This section describes the con\214guration \214le i\
+n detail, including hints on ho)112 417.6 R 2.764(wt)-.25 G 2.764(ow)426.294
+417.6 S .264(rite one of your)441.278 417.6 R -.25(ow)87 429.6 S 2.5(ni).25 G
+2.5(fy)109.25 429.6 S(ou ha)120.08 429.6 Q .3 -.15(ve t)-.2 H(o.).15 E .648(Th\
+ere is one point that should be made clear immediately: the syntax of the con\
+\214guration \214le is)112 445.8 R 1.076
+(designed to be reasonably easy to parse, since this is done e)87 457.8 R -.15
+(ve)-.25 G 1.077(ry time).15 F F2(sendmail)3.577 E F1 1.077
+(starts up, rather than)3.577 F(easy for a human to read or write.)87 469.8 Q
+(On the \231future project\232 list is a con\214guration-\214le compiler)5 E(.)
+-.55 E(An o)112 486 Q -.15(ve)-.15 G(rvie).15 E 2.5(wo)-.25 G 2.5(ft)170.88 486
+S(he con\214guration \214le is gi)179.49 486 Q -.15(ve)-.25 G 2.5<6e8c>.15 G
+(rst, follo)301.59 486 Q(wed by details of the semantics.)-.25 E F0 2.5
+(5.1. Con\214guration)87 510 R(File Lines)2.5 E F1 1.316
+(The con\214guration \214le is or)127 526.2 R -.05(ga)-.18 G 1.316
+(nized as a series of lines, each of which be).05 F 1.315(gins with a single)
+-.15 F .741(character de\214ning the semantics for the rest of the line.)102
+538.2 R .742(Lines be)5.742 F .742(ginning with a space or a tab are)-.15 F
+1.149
+(continuation lines \(although the semantics are not well de\214ned in man)102
+550.2 R 3.648(yp)-.15 G 3.648(laces\). Blank)407.516 550.2 R 1.148(lines and)
+3.648 F(lines be)102 562.2 Q(ginning with a sharp symbol \(`#'\) are comments.)
+-.15 E F0 2.5(5.1.1. R)102 586.2 R(and S \212 r)2.5 E(ewriting rules)-.18 E F1
+.406(The core of address parsing are the re)142 602.4 R .406(writing rules.)
+-.25 F .407(These are an ordered production sys-)5.407 F(tem.)117 614.4 Q F2
+(Sendmail)5.283 E F1 .283(scans through the set of re)2.783 F .282
+(writing rules looking for a match on the left hand side)-.25 F .131
+(\(LHS\) of the rule.)117 626.4 R .131(When a rule matches, the address is rep\
+laced by the right hand side \(RHS\) of)5.131 F(the rule.)117 638.4 Q 1.126
+(There are se)142 654.6 R -.15(ve)-.25 G 1.126(ral sets of re).15 F 1.126
+(writing rules.)-.25 F 1.126(Some of the re)6.126 F 1.125
+(writing sets are used internally)-.25 F .21(and must ha)117 666.6 R .51 -.15
+(ve s)-.2 H .21(peci\214c semantics.).15 F .21(Other re)5.21 F .21
+(writing sets do not ha)-.25 F .51 -.15(ve s)-.2 H .21
+(peci\214cally assigned seman-).15 F
+(tics, and may be referenced by the mailer de\214nitions or by other re)117
+678.6 Q(writing sets.)-.25 E(The syntax of these tw)142 694.8 Q 2.5(oc)-.1 G
+(ommands are:)244.38 694.8 Q F0(S)157 711 Q F2(n)A EP
+%%Page: 25 20
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-25)452.9 60 Q/F1 10/Times-Roman@0 SF .278
+(Sets the current ruleset being collected to)117 96 R/F2 10/Times-Italic@0 SF
+(n)2.778 E F1 5.278(.I)C 2.778(fy)302.524 96 S .278(ou be)313.632 96 R .278
+(gin a ruleset more than once it deletes the)-.15 F(old de\214nition.)117 108 Q
+F0(R)157 124.2 Q F2(lhs rhs comments)A F1 .303(The \214elds must be separated \
+by at least one tab character; there may be embedded spaces in the)117 140.4 R
+2.739(\214elds. The)117 152.4 R F2(lhs)2.739 E F1 .239
+(is a pattern that is applied to the input.)2.739 F .238
+(If it matches, the input is re)5.238 F .238(written to the)-.25 F F2(rhs)117
+164.4 Q F1 5(.T)C(he)143.39 164.4 Q F2(comments)2.5 E F1(are ignored.)2.5 E
+2.265(Macro e)142 180.6 R 2.265(xpansions of the form)-.15 F F0($)4.765 E F2(x)
+A F1 2.266(are performed when the con\214guration \214le is read.)4.765 F .081
+(Expansions of the form)117 192.6 R F0($&)2.581 E F2(x)A F1 .081
+(are performed at run time using a some)2.581 F .08
+(what less general algorithm.)-.25 F .639
+(This for is intended only for referencing internally de\214ned macros such as)
+117 204.6 R F0($h)3.139 E F1 .639(that are changed)3.139 F(at runtime.)117
+216.6 Q F0 2.5(5.1.1.1. The)117 240.6 R(left hand side)2.5 E F1 1.617
+(The left hand side of re)157 256.8 R 1.617(writing rules contains a pattern.)
+-.25 F 1.617(Normal w)6.617 F 1.617(ords are simply)-.1 F(matched directly)132
+268.8 Q 5(.M)-.65 G(etasyntax is introduced using a dollar sign.)214.67 268.8 Q
+(The metasymbols are:)5 E F0($*)172 285 Q F1(Match zero or more tok)192.14 285
+Q(ens)-.1 E F0($+)172 297 Q F1(Match one or more tok)9.44 E(ens)-.1 E F0<24ad>
+172 309 Q F1(Match e)9.44 E(xactly one tok)-.15 E(en)-.1 E F0($=)172 321 Q F2
+(x)A F1(Match an)5 E 2.5(yp)-.15 G(hrase in class)241.98 321 Q F2(x)2.5 E F0
+($~)172 333 Q F2(x)A F1(Match an)7.37 E 2.5(yw)-.15 G(ord not in class)244.1
+333 Q F2(x)2.5 E F1 .498(If an)132 349.2 R 2.998(yo)-.15 G 2.998(ft)163.946
+349.2 S .499(hese match, the)173.054 349.2 R 2.999(ya)-.15 G .499
+(re assigned to the symbol)248.271 349.2 R F0($)2.999 E F2(n)A F1 .499
+(for replacement on the right hand)2.999 F(side, where)132 361.2 Q F2(n)2.5 E
+F1(is the inde)2.5 E 2.5(xi)-.15 G 2.5(nt)238.78 361.2 S(he LHS.)249.06 361.2 Q
+-.15(Fo)5 G 2.5(re).15 G(xample, if the LHS:)307.92 361.2 Q($\255:$+)172 377.4
+Q(is applied to the input:)132 393.6 Q(UCB)172 409.8 Q(ARP)-.35 E(A:eric)-.92 E
+(the rule will match, and the v)132 426 Q(alues passed to the RHS will be:)-.25
+E 7.5($1 UCB)172 442.2 R(ARP)-.35 E(A)-.92 E 7.5($2 eric)172 454.2 R
+(Additionally)157 474.6 Q 3.398(,t)-.65 G .898(he LHS can include)215.588 474.6
+R F0($@)3.398 E F1 .898(to match zero tok)3.398 F 3.398(ens. This)-.1 F(is)
+3.398 E F2(not)3.398 E F1 .898(bound to a)3.398 F F0($)132 486.6 Q F2(N)A F1
+.837(on the RHS, and is normally only used when it stands alone in order to ma\
+tch the null)3.337 F(input.)132 498.6 Q F0 2.5(5.1.1.2. The)117 522.6 R
+(right hand side)2.5 E F1 .526(When the left hand side of a re)157 538.8 R .525
+(writing rule matches, the input is deleted and replaced)-.25 F .931
+(by the right hand side.)132 550.8 R -.8(To)5.932 G -.1(ke).8 G .932
+(ns are copied directly from the RHS unless the).1 F 3.432(yb)-.15 G -.15(eg)
+457.846 550.8 S .932(in with a).15 F(dollar sign.)132 562.8 Q(Metasymbols are:)
+5 E F0($)172 579 Q F2(n)A F1(Substitute inde\214nite tok)222.55 579 Q(en)-.1 E
+F2(n)2.5 E F1(from LHS)2.5 E F0($[)172 591 Q F2(name)A F0($])A F1(Canonicalize)
+222.55 591 Q F2(name)2.5 E F0($\()172 603 Q F2(map k)A -.3(ey)-.1 G F0($@)2.8 E
+F2(ar)A(guments)-.37 E F0($:)2.5 E F2(default)A F0($\))2.5 E F1(Generalized k)
+222.55 615 Q -.15(ey)-.1 G(ed mapping function).15 E F0($>)172 627 Q F2(n)A F1
+(\231Call\232 ruleset)222.55 627 Q F2(n)2.5 E F0($#)172 639 Q F2(mailer)A F1
+(Resolv)222.55 639 Q 2.5(et)-.15 G(o)259.9 639 Q F2(mailer)2.5 E F0($@)172 651
+Q F2(host)A F1(Specify)222.55 651 Q F2(host)2.5 E F0($:)172 663 Q F2(user)A F1
+(Specify)222.55 663 Q F2(user)2.5 E F1(The)157 683.4 Q F0($)3.013 E F2(n)A F1
+.513(syntax substitutes the corresponding v)3.013 F .513(alue from a)-.25 F F0
+($+)3.013 E F1(,)A F0<24ad>3.013 E F1(,)A F0($*)3.012 E F1(,)A F0($=)3.012 E F1
+3.012(,o)C(r)461.876 683.4 Q F0($~)3.012 E F1(match)3.012 E(on the LHS.)132
+695.4 Q(It may be used an)5 E(ywhere.)-.15 E 2.7(Ah)157 711.6 S .2
+(ost name enclosed between)171.92 711.6 R F0($[)2.7 E F1(and)2.7 E F0($])2.7 E
+F1 .2(is look)2.7 F .201(ed up using the)-.1 F F2 -.1(ge)2.701 G(thostent).1 E
+F1 .201(\(3\) routines)1.666 F EP
+%%Page: 26 21
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-26 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 3.333
+(and replaced by the canonical name)132 98 R/F2 7/Times-Roman@0 SF(8)291.675 94
+Q F1 8.333(.F)295.175 98 S 3.333(or e)311.418 98 R 3.332
+(xample, \231$[csam$]\232 might become \231lbl-)-.15 F 1.923
+(csam.arpa\232 and \231$[[128.32.130.2]$]\232 w)132 110 R 1.923
+(ould become \231v)-.1 F(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU.)
+.65 E<9a>-.7 E/F3 10/Times-Italic@0 SF(Send-)6.924 E(mail)132 122 Q F1 .436
+(recognizes it')2.936 F 2.936(sn)-.55 G .436
+(umeric IP address without calling the name serv)218.578 122 R .435
+(er and replaces it with)-.15 F(it')132 134 Q 2.5(sc)-.55 G(anonical name.)
+151.17 134 Q(The)157 150.2 Q F0($\()2.861 E F1(...)2.861 E F0($\))5.361 E F1
+.361(syntax is a more general form of lookup; it uses a named map instead of)
+2.861 F .028(an implicit map.)132 162.2 R .027
+(If no lookup is found, the indicated)5.027 F F3(default)2.527 E F1 .027
+(is inserted; if no def)2.527 F .027(ault is spec-)-.1 F
+(i\214ed and no lookup matches, the v)132 174.2 Q(alue is left unchanged.)-.25
+E(The)157 190.4 Q F0($>)3.571 E F3(n)A F1 1.071
+(syntax causes the remainder of the line to be substituted as usual and then)
+3.571 F .572(passed as the ar)132 202.4 R .572(gument to ruleset)-.18 F F3(n)
+3.072 E F1 5.572(.T)C .572(he \214nal v)288.854 202.4 R .572(alue of ruleset)
+-.25 F F3(n)3.072 E F1 .571(then becomes the substitu-)3.072 F
+(tion for this rule.)132 214.4 Q(The)157 230.6 Q F0($#)3.358 E F1 .858
+(syntax should)3.358 F F3(only)3.358 E F1 .858
+(be used in ruleset zero or a subroutine of ruleset zero.)3.358 F(It)5.859 E
+1.1(causes e)132 242.6 R -.25(va)-.25 G 1.1
+(luation of the ruleset to terminate immediately).25 F 3.6(,a)-.65 G 1.1
+(nd signals to)377.11 242.6 R F3(sendmail)3.6 E F1 1.1(that the)3.6 F
+(address has completely resolv)132 254.6 Q 2.5(ed. The)-.15 F
+(complete syntax is:)2.5 E F0($#)172 270.8 Q F3(mailer)A F0($@)2.5 E F3(host)A
+F0($:)2.5 E F3(user)A F1 .394(This speci\214es the {mailer)132 287 R 2.894(,h)
+-.4 G .394(ost, user} 3-tuple necessary to direct the mailer)245.466 287 R
+5.394(.I)-.55 G 2.894(ft)447.548 287 S .394(he mailer is)456.552 287 R .135
+(local the host part may be omitted)132 301 R F2(9)268.91 297 Q F1 5.135(.T)
+272.41 301 S(he)286.155 301 Q F3(mailer)2.635 E F1 .136(must be a single w)
+2.636 F .136(ord, b)-.1 F .136(ut the)-.2 F F3(host)2.636 E F1(and)2.636 E F3
+(user)2.636 E F1 .252(may be multi-part.)132 313 R .252(If the)5.252 F F3
+(mailer)2.752 E F1 .252(is the b)2.752 F .252(uiltin IPC mailer)-.2 F 2.752(,t)
+-.4 G(he)369.722 313 Q F3(host)2.752 E F1 .251(may be a colon-separated)2.752 F
+2.439(list of hosts that are searched in order for the \214rst w)132 325 R
+2.439(orking address \(e)-.1 F 2.439(xactly lik)-.15 F 4.939(eM)-.1 G(X)496.78
+325 Q 5.185(records\). The)132 337 R F3(user)5.185 E F1 2.685(is later re)5.185
+F 2.685(written by the mailer)-.25 F 2.685(-speci\214c en)-.2 F -.15(ve)-.4 G
+2.685(lope re).15 F 2.685(writing set and)-.25 F .122(assigned to the)132 349 R
+F0($u)2.622 E F1 2.622(macro. As)2.622 F 2.622(as)2.622 G .123
+(pecial case, if the v)264.784 349 R .123(alue to)-.25 F F0($#)2.623 E F1 .123
+(is \231local\232 and the \214rst charac-)2.623 F .458(ter of the)132 361 R F0
+($:)2.958 E F1 -.25(va)2.958 G .458
+(lue is \231@\232, the \231@\232 is stripped of).25 F .457
+(f, and a \215ag is set in the address descriptor)-.25 F
+(that causes sendmail to not do ruleset 5 processing.)132 373 Q(Normally)157
+389.2 Q 3.593(,ar)-.65 G 1.093
+(ule that matches is retried, that is, the rule loops until it f)212.136 389.2
+R 3.594(ails. A)-.1 F(RHS)3.594 E .209(may also be preceded by a)132 401.2 R F0
+($@)2.709 E F1 .209(or a)2.709 F F0($:)2.708 E F1 .208(to change this beha)
+2.708 F(vior)-.2 E 5.208(.A)-.55 G F0($@)398.338 401.2 Q F1 .208
+(pre\214x causes the rule-)2.708 F .527
+(set to return with the remainder of the RHS as the v)132 413.2 R 3.027
+(alue. A)-.25 F F0($:)3.028 E F1 .528(pre\214x causes the rule to ter)3.028 F
+(-)-.2 E .295(minate immediately)132 425.2 R 2.795(,b)-.65 G .294
+(ut the ruleset to continue; this can be used to a)221.46 425.2 R -.2(vo)-.2 G
+.294(id continued applica-).2 F(tion of a rule.)132 437.2 Q
+(The pre\214x is stripped before continuing.)5 E(The)157 453.4 Q F0($@)2.5 E F1
+(and)2.5 E F0($:)2.5 E F1(pre\214x)2.5 E(es may precede a)-.15 E F0($>)2.5 E F1
+(spec; for e)2.5 E(xample:)-.15 E 20.19(R$+ $:)172 469.6 R($>7 $1)2.5 E .256
+(matches an)132 485.8 R .256(ything, passes that to ruleset se)-.15 F -.15(ve)
+-.25 G .256(n, and continues; the).15 F F0($:)2.756 E F1 .256
+(is necessary to a)2.756 F -.2(vo)-.2 G .256(id an).2 F(in\214nite loop.)132
+497.8 Q .051(Substitution occurs in the order described, that is, parameters f\
+rom the LHS are substi-)157 514 R .556(tuted, hostnames are canonicalized, \
+\231subroutines\232 are called, and \214nally)132 526 R F0($#)3.056 E F1(,)A F0
+($@)3.056 E F1 3.056(,a)C(nd)467.346 526 Q F0($:)3.057 E F1(are)3.057 E
+(processed.)132 538 Q F0 2.5(5.1.1.3. Semantics)117 562 R(of r)2.5 E
+(ewriting rule sets)-.18 E F1 2.922(There are \214v)157 578.2 R 5.422(er)-.15 G
+-.25(ew)226.976 578.2 S 2.922(riting sets that ha).25 F 3.222 -.15(ve s)-.2 H
+2.922(peci\214c semantics.).15 F 2.921(These are related as)7.921 F
+(depicted by \214gure 2.)132 590.2 Q 1.091
+(Ruleset three should turn the address into \231canonical form.)157 606.4 R
+6.092<9a54>-.7 G 1.092(his form should ha)416.914 606.4 R -.15(ve)-.2 G
+(the basic syntax:)132 618.4 Q(local-part@host-domain-spec)172 634.6 Q 1.296
+(If no \231@\232 sign is speci\214ed, then the host-domain-spec)132 650.8 R F3
+(may)3.796 E F1 1.295(be appended from the sender)3.796 F 1.284
+(address \(if the)132 662.8 R F0(C)3.784 E F1 1.284
+(\215ag is set in the mailer de\214nition corresponding to the)3.784 F F3
+(sending)3.784 E F1(mailer\).)3.784 E .32 LW 76 672.4 72 672.4 DL 80 672.4 76
+672.4 DL 84 672.4 80 672.4 DL 88 672.4 84 672.4 DL 92 672.4 88 672.4 DL 96
+672.4 92 672.4 DL 100 672.4 96 672.4 DL 104 672.4 100 672.4 DL 108 672.4 104
+672.4 DL 112 672.4 108 672.4 DL 116 672.4 112 672.4 DL 120 672.4 116 672.4 DL
+124 672.4 120 672.4 DL 128 672.4 124 672.4 DL 132 672.4 128 672.4 DL 136 672.4
+132 672.4 DL 140 672.4 136 672.4 DL 144 672.4 140 672.4 DL 148 672.4 144 672.4
+DL 152 672.4 148 672.4 DL 156 672.4 152 672.4 DL 160 672.4 156 672.4 DL 164
+672.4 160 672.4 DL 168 672.4 164 672.4 DL 172 672.4 168 672.4 DL 176 672.4 172
+672.4 DL 180 672.4 176 672.4 DL 184 672.4 180 672.4 DL 188 672.4 184 672.4 DL
+192 672.4 188 672.4 DL 196 672.4 192 672.4 DL 200 672.4 196 672.4 DL 204 672.4
+200 672.4 DL 208 672.4 204 672.4 DL 212 672.4 208 672.4 DL 216 672.4 212 672.4
+DL/F4 5/Times-Roman@0 SF(8)93.6 682.8 Q/F5 8/Times-Roman@0 SF
+(This is actually completely equi)3.2 I -.2(va)-.2 G(lent to $\(host).2 E/F6 8
+/Times-Italic@0 SF(hostname)2 E F5 2($\). In)B(particular)2 E 2(,a)-.32 G/F7 8
+/Times-Bold@0 SF($:)A F5(def)2 E(ault can be used.)-.08 E F4(9)93.6 696.4 Q F5
+-.88(Yo)3.2 K 2.208(um).88 G .208(ay w)117.428 699.6 R .208
+(ant to use it for special \231per user\232 e)-.08 F 2.208(xtensions. F)-.12 F
+.208(or e)-.12 F .208
+(xample, at CMU you can send email to \231jgm+foo\232; the part af-)-.12 F(ter\
+ the plus sign is not part of the user name, and is passed to the local mailer\
+ for local use.)72 709.2 Q EP
+%%Page: 27 22
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-27)452.9 60 Q .4 LW 77 108 72 108 DL 79 108 74 108 DL 84 108 79 108 DL
+89 108 84 108 DL 94 108 89 108 DL 99 108 94 108 DL 104 108 99 108 DL 109 108
+104 108 DL 114 108 109 108 DL 119 108 114 108 DL 124 108 119 108 DL 129 108 124
+108 DL 134 108 129 108 DL 139 108 134 108 DL 144 108 139 108 DL 149 108 144 108
+DL 154 108 149 108 DL 159 108 154 108 DL 164 108 159 108 DL 169 108 164 108 DL
+174 108 169 108 DL 179 108 174 108 DL 184 108 179 108 DL 189 108 184 108 DL 194
+108 189 108 DL 199 108 194 108 DL 204 108 199 108 DL 209 108 204 108 DL 214 108
+209 108 DL 219 108 214 108 DL 224 108 219 108 DL 229 108 224 108 DL 234 108 229
+108 DL 239 108 234 108 DL 244 108 239 108 DL 249 108 244 108 DL 254 108 249 108
+DL 259 108 254 108 DL 264 108 259 108 DL 269 108 264 108 DL 274 108 269 108 DL
+279 108 274 108 DL 284 108 279 108 DL 289 108 284 108 DL 294 108 289 108 DL 299
+108 294 108 DL 304 108 299 108 DL 309 108 304 108 DL 314 108 309 108 DL 319 108
+314 108 DL 324 108 319 108 DL 329 108 324 108 DL 334 108 329 108 DL 339 108 334
+108 DL 344 108 339 108 DL 349 108 344 108 DL 354 108 349 108 DL 359 108 354 108
+DL 364 108 359 108 DL 369 108 364 108 DL 374 108 369 108 DL 379 108 374 108 DL
+384 108 379 108 DL 389 108 384 108 DL 394 108 389 108 DL 399 108 394 108 DL 404
+108 399 108 DL 409 108 404 108 DL 414 108 409 108 DL 419 108 414 108 DL 424 108
+419 108 DL 429 108 424 108 DL 434 108 429 108 DL 439 108 434 108 DL 444 108 439
+108 DL 449 108 444 108 DL 454 108 449 108 DL 459 108 454 108 DL 464 108 459 108
+DL 469 108 464 108 DL 474 108 469 108 DL 479 108 474 108 DL 484 108 479 108 DL
+489 108 484 108 DL 494 108 489 108 DL 499 108 494 108 DL 504 108 499 108 DL/F1
+10/Times-Roman@0 SF(addr)91.915 202.4 Q 133.2 200.4 111.6 200.4 DL 133.2 200.4
+126 202.2 DL 133.2 200.4 126 198.6 DL(3)141.5 202.4 Q 133.2 189.6 133.2 211.2
+DL 154.8 189.6 133.2 189.6 DL 154.8 211.2 154.8 189.6 DL 133.2 211.2 154.8
+211.2 DL 176.4 200.4 154.8 200.4 DL 176.4 200.4 169.2 202.2 DL 176.4 200.4
+169.2 198.6 DL(D)183.59 202.4 Q 176.4 189.6 176.4 211.2 DL 198 189.6 176.4
+189.6 DL 198 211.2 198 189.6 DL 176.4 211.2 198 211.2 DL 219.6 200.4 198 200.4
+DL 277.2 182.4 255.6 182.4 DL 277.2 182.4 270 184.2 DL 277.2 182.4 270 180.6 DL
+(1)285.5 184.4 Q 277.2 171.6 277.2 193.2 DL 298.8 171.6 277.2 171.6 DL 298.8
+193.2 298.8 171.6 DL 277.2 193.2 298.8 193.2 DL 320.4 182.4 298.8 182.4 DL
+320.4 182.4 313.2 184.2 DL 320.4 182.4 313.2 180.6 DL(S)328.42 184.4 Q 320.4
+171.6 320.4 193.2 DL 342 171.6 320.4 171.6 DL 342 193.2 342 171.6 DL 320.4
+193.2 342 193.2 DL 363.6 182.4 342 182.4 DL 277.2 218.4 255.6 218.4 DL 277.2
+218.4 270 220.2 DL 277.2 218.4 270 216.6 DL(2)285.5 220.4 Q 277.2 207.6 277.2
+229.2 DL 298.8 207.6 277.2 207.6 DL 298.8 229.2 298.8 207.6 DL 277.2 229.2
+298.8 229.2 DL 320.4 218.4 298.8 218.4 DL 320.4 218.4 313.2 220.2 DL 320.4
+218.4 313.2 216.6 DL(R)327.865 220.4 Q 320.4 207.6 320.4 229.2 DL 342 207.6
+320.4 207.6 DL 342 229.2 342 207.6 DL 320.4 229.2 342 229.2 DL 363.6 218.4 342
+218.4 DL 421.2 200.4 399.6 200.4 DL 421.2 200.4 414 202.2 DL 421.2 200.4 414
+198.6 DL(4)429.5 202.4 Q 421.2 189.6 421.2 211.2 DL 442.8 189.6 421.2 189.6 DL
+442.8 211.2 442.8 189.6 DL 421.2 211.2 442.8 211.2 DL 464.4 200.4 442.8 200.4
+DL 464.4 200.4 457.2 202.2 DL 464.4 200.4 457.2 198.6 DL(msg)466.865 202.4 Q
+255.6 182.4 219.6 200.4 DL 255.6 218.4 219.6 200.4 DL 399.6 200.4 363.6 182.4
+DL 399.6 200.4 363.6 218.4 DL 208.8 146.4 187.2 146.4 DL 208.8 146.4 201.6
+148.2 DL 208.8 146.4 201.6 144.6 DL(0)217.1 148.4 Q 208.8 135.6 208.8 157.2 DL
+230.4 135.6 208.8 135.6 DL 230.4 157.2 230.4 135.6 DL 208.8 157.2 230.4 157.2
+DL 252 146.4 230.4 146.4 DL 252 146.4 244.8 148.2 DL 252 146.4 244.8 144.6 DL
+(resolv)265.69 148.4 Q(ed address)-.15 E 187.2 146.4 162 200.4 DL
+(Figure 2 \212 Re)216.045 248.4 Q(writing set semantics)-.25 E 2.5(D\212s)
+209.35 260.4 S(ender domain addition)235.46 260.4 Q 2.5(S\212m)209.35 272.4 S
+(ailer)237.69 272.4 Q(-speci\214c sender re)-.2 E(writing)-.25 E 2.5(R\212m)
+209.35 284.4 S(ailer)238.8 284.4 Q(-speci\214c recipient re)-.2 E(writing)-.25
+E 77 296.4 72 296.4 DL 79 296.4 74 296.4 DL 84 296.4 79 296.4 DL 89 296.4 84
+296.4 DL 94 296.4 89 296.4 DL 99 296.4 94 296.4 DL 104 296.4 99 296.4 DL 109
+296.4 104 296.4 DL 114 296.4 109 296.4 DL 119 296.4 114 296.4 DL 124 296.4 119
+296.4 DL 129 296.4 124 296.4 DL 134 296.4 129 296.4 DL 139 296.4 134 296.4 DL
+144 296.4 139 296.4 DL 149 296.4 144 296.4 DL 154 296.4 149 296.4 DL 159 296.4
+154 296.4 DL 164 296.4 159 296.4 DL 169 296.4 164 296.4 DL 174 296.4 169 296.4
+DL 179 296.4 174 296.4 DL 184 296.4 179 296.4 DL 189 296.4 184 296.4 DL 194
+296.4 189 296.4 DL 199 296.4 194 296.4 DL 204 296.4 199 296.4 DL 209 296.4 204
+296.4 DL 214 296.4 209 296.4 DL 219 296.4 214 296.4 DL 224 296.4 219 296.4 DL
+229 296.4 224 296.4 DL 234 296.4 229 296.4 DL 239 296.4 234 296.4 DL 244 296.4
+239 296.4 DL 249 296.4 244 296.4 DL 254 296.4 249 296.4 DL 259 296.4 254 296.4
+DL 264 296.4 259 296.4 DL 269 296.4 264 296.4 DL 274 296.4 269 296.4 DL 279
+296.4 274 296.4 DL 284 296.4 279 296.4 DL 289 296.4 284 296.4 DL 294 296.4 289
+296.4 DL 299 296.4 294 296.4 DL 304 296.4 299 296.4 DL 309 296.4 304 296.4 DL
+314 296.4 309 296.4 DL 319 296.4 314 296.4 DL 324 296.4 319 296.4 DL 329 296.4
+324 296.4 DL 334 296.4 329 296.4 DL 339 296.4 334 296.4 DL 344 296.4 339 296.4
+DL 349 296.4 344 296.4 DL 354 296.4 349 296.4 DL 359 296.4 354 296.4 DL 364
+296.4 359 296.4 DL 369 296.4 364 296.4 DL 374 296.4 369 296.4 DL 379 296.4 374
+296.4 DL 384 296.4 379 296.4 DL 389 296.4 384 296.4 DL 394 296.4 389 296.4 DL
+399 296.4 394 296.4 DL 404 296.4 399 296.4 DL 409 296.4 404 296.4 DL 414 296.4
+409 296.4 DL 419 296.4 414 296.4 DL 424 296.4 419 296.4 DL 429 296.4 424 296.4
+DL 434 296.4 429 296.4 DL 439 296.4 434 296.4 DL 444 296.4 439 296.4 DL 449
+296.4 444 296.4 DL 454 296.4 449 296.4 DL 459 296.4 454 296.4 DL 464 296.4 459
+296.4 DL 469 296.4 464 296.4 DL 474 296.4 469 296.4 DL 479 296.4 474 296.4 DL
+484 296.4 479 296.4 DL 489 296.4 484 296.4 DL 494 296.4 489 296.4 DL 499 296.4
+494 296.4 DL 504 296.4 499 296.4 DL(Ruleset three is applied by)132 332.4 Q/F2
+10/Times-Italic@0 SF(sendmail)2.5 E F1(before doing an)2.5 E(ything with an)
+-.15 E 2.5(ya)-.15 G(ddress.)411.39 332.4 Q .506(Ruleset zero is applied after\
+ ruleset three to addresses that are going to actually spec-)157 348.6 R .295
+(ify recipients.)132 360.6 R .295(It must resolv)5.295 F 2.795(et)-.15 G 2.795
+(oa)258.035 360.6 S F2({mailer).001 E 2.796(,h)-1.11 G .296(ost, user})312.362
+360.6 R F1 2.796(triple. The)2.796 F F2(mailer)2.796 E F1 .296
+(must be de\214ned in)2.796 F .561
+(the mailer de\214nitions from the con\214guration \214le.)132 372.6 R(The)
+5.561 E F2(host)3.061 E F1 .56(is de\214ned into the)3.061 F F0($h)3.06 E F1
+.56(macro for)3.06 F(use in the ar)132 384.6 Q(gv e)-.18 E
+(xpansion of the speci\214ed mailer)-.15 E(.)-.55 E 1.356(Rulesets one and tw)
+157 400.8 R 3.856(oa)-.1 G 1.357
+(re applied to all sender and recipient addresses respecti)254.534 400.8 R -.15
+(ve)-.25 G(ly).15 E(.)-.65 E(The)132 412.8 Q 2.5(ya)-.15 G
+(re applied before an)159.34 412.8 Q 2.5(ys)-.15 G
+(peci\214cation in the mailer de\214nition.)250.27 412.8 Q(The)5 E 2.5(ym)-.15
+G(ust ne)429 412.8 Q -.15(ve)-.25 G 2.5(rr).15 G(esolv)470.81 412.8 Q(e.)-.15 E
+.266(Ruleset four is applied to all addresses in the message.)157 429 R .265
+(It is typically used to translate)5.265 F(internal to e)132 441 Q
+(xternal form.)-.15 E F0 2.5(5.1.1.4. IPC)117 465 R(mailers)2.5 E F1 .332
+(Some special processing occurs if the ruleset zero resolv)157 481.2 R .333
+(es to an IPC mailer \(that is, a)-.15 F .242
+(mailer that has \231[IPC]\232 listed as the P)132 493.2 R .241(ath in the)-.15
+F F0(M)2.741 E F1 .241(con\214guration line.)2.741 F .241(The host name passed)
+5.241 F .884(after \231$@\232 has MX e)132 505.2 R .885
+(xpansion performed; this looks the name up in DNS to \214nd alternate)-.15 F
+(deli)132 517.2 Q -.15(ve)-.25 G(ry sites.).15 E(The host name can also be pro)
+157 533.4 Q(vided as a dotted quad in square brack)-.15 E(ets; for e)-.1 E
+(xample:)-.15 E([128.32.149.78])172 549.6 Q(This causes direct con)132 565.8 Q
+-.15(ve)-.4 G(rsion of the numeric v).15 E(alue to a TCP/IP host address.)-.25
+E .894(The host name passed in after the \231$@\232 may also be a colon-separa\
+ted list of hosts.)157 582 R .629(Each is separately MX e)132 594 R .629
+(xpanded and the results are concatenated to mak)-.15 F 3.13(e\()-.1 G .63
+(essentially\) one)440.88 594 R .379(long MX list.)132 606 R .378
+(The intent here is to create \231f)5.379 F(ak)-.1 E .378
+(e\232 MX records that are not published in DNS)-.1 F(for pri)132 618 Q -.25
+(va)-.25 G(te internal netw).25 E(orks.)-.1 E .17
+(As a \214nal special case, the host name can be passed in as a te)157 634.2 R
+.17(xt string in square brack-)-.15 F(ets:)132 646.2 Q([ucb)172 662.4 Q -.25
+(va)-.15 G(x.berk).25 E(ele)-.1 E -.65(y.)-.15 G(edu]).65 E 1.245(This form a)
+132 678.6 R -.2(vo)-.2 G 1.245(ids the MX mapping.).2 F F0(N.B.:)6.244 E F1
+1.244(This is intended only for situations where you)3.744 F(ha)132 690.6 Q
+.814 -.15(ve a n)-.2 H(etw).15 E .514(ork \214re)-.1 F -.1(wa)-.25 G .514
+(ll, so that your MX record points to a g).1 F(ate)-.05 E -.1(wa)-.25 G 3.014
+(ym).1 G .514(achine; this machine)420.762 690.6 R 1.604
+(could then do direct deli)132 702.6 R -.15(ve)-.25 G 1.604
+(ry to machines within your local domain.).15 F 1.603(Use of this feature)6.603
+F(directly violates RFC 1123 section 5.3.5: it should not be used lightly)132
+714.6 Q(.)-.65 E EP
+%%Page: 28 23
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-28 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(5.1.2. D)102 96 R 2.5<8a64>2.5 G
+(e\214ne macr)157.28 96 Q(o)-.18 E/F1 10/Times-Roman@0 SF .546
+(Macros are named with a single character)142 112.2 R 5.546(.T)-.55 G .547
+(hese may be selected from the entire ASCII)325.492 112.2 R .892(set, b)117
+124.2 R .892(ut user)-.2 F .892
+(-de\214ned macros should be selected from the set of upper case letters only)
+-.2 F 5.892(.L)-.65 G -.25(ow)484.26 124.2 S(er).25 E
+(case letters and special symbols are used internally)117 136.2 Q(.)-.65 E
+(The syntax for macro de\214nitions is:)142 152.4 Q F0(D)157 168.6 Q/F2 10
+/Times-Italic@0 SF 1.666(xv)C(al)-1.666 E F1(where)117 184.8 Q F2(x)2.5 E F1
+(is the name of the macro and)2.5 E F2(val)2.5 E F1(is the v)2.5 E
+(alue it should ha)-.25 E -.15(ve)-.2 G(.).15 E 1.085
+(Macros are interpolated using the construct)142 201 R F0($)3.585 E F2(x)A F1
+3.585(,w)C(here)346.775 201 Q F2(x)3.585 E F1 1.085
+(is the name of the macro to be)3.585 F 3.45(interpolated. This)117 213 R .95
+(interpolation is done when the con\214guration \214le is read, e)3.45 F .95
+(xcept in)-.15 F F0(M)3.45 E F1(lines.)3.45 E(The special construct)117 225 Q
+F0($&)2.5 E F2(x)A F1(can be used in)2.5 E F0(R)2.5 E F1
+(lines to get deferred interpolation.)2.5 E
+(Conditionals can be speci\214ed using the syntax:)142 241.2 Q($?x te)157 257.4
+Q(xt1 $| te)-.15 E(xt2 $.)-.15 E .245(This interpolates)117 273.6 R F2(te)2.745
+E(xt1)-.2 E F1 .245(if the macro)2.745 F F0($x)2.745 E F1 .245(is set, and)
+2.745 F F2(te)2.745 E(xt2)-.2 E F1 2.745(otherwise. The)2.745 F .246
+(\231else\232 \()2.746 F F0($|)A F1 2.746(\)c)C .246(lause may be)451.298 273.6
+R(omitted.)117 285.6 Q(Lo)142 301.8 Q .262(wer case macro names are reserv)-.25
+F .262(ed to ha)-.15 F .561 -.15(ve s)-.2 H .261
+(pecial semantics, used to pass information).15 F 1.162(in or out of)117 313.8
+R F2(sendmail)3.663 E F1 3.663(,a)C 1.163(nd special characters are reserv)
+215.583 313.8 R 1.163(ed to pro)-.15 F 1.163(vide conditionals, etc.)-.15 F
+(Upper)6.163 E(case names \(that is,)117 325.8 Q F0($A)2.5 E F1(through)2.5 E
+F0($Z)2.5 E F1 2.5(\)a)C(re speci\214cally reserv)267.53 325.8 Q
+(ed for con\214guration \214le authors.)-.15 E .053(The follo)142 342 R .053
+(wing macros are de\214ned and/or used internally by)-.25 F F2(sendmail)2.552 E
+F1 .052(for interpolation into)2.552 F(ar)117 354 Q(gv')-.18 E 5.178(sf)-.55 G
+2.678(or mailers or for other conte)149.768 354 R 5.179(xts. The)-.15 F 2.679
+(ones mark)5.179 F 2.679(ed \207 are information passed into)-.1 F(sendmail)117
+368 Q/F3 7/Times-Roman@0 SF(10)153.11 364 Q F1 4.232(,t)160.11 368 S 1.732
+(he ones mark)169.622 368 R 1.732
+(ed \210 are information passed both in and out of sendmail, and the)-.1 F
+(unmark)117 380 Q 2.177(ed macros are passed out of sendmail b)-.1 F 2.177
+(ut are not otherwise used internally)-.2 F 7.177(.T)-.65 G(hese)486.23 380 Q
+(macros are:)117 392 Q($a)117 408.2 Q F0(The origination date in RFC 822 f)142
+408.2 Q(ormat.)-.25 E F1($b)117 424.4 Q F0(The curr)142 424.4 Q
+(ent date in RFC 822 f)-.18 E(ormat.)-.25 E F1($c)117 440.6 Q F0
+(The hop count.)142 440.6 Q F1($d)117 456.8 Q F0(The curr)142 456.8 Q
+(ent date in UNIX \(ctime\) f)-.18 E(ormat.)-.25 E F1($e\207)117 473 Q F0 1.342
+(The SMTP entry message.)142 473 R F1 1.341
+(This is printed out when SMTP starts up.)6.342 F 1.341(The \214rst w)6.341 F
+(ord)-.1 E .428(must be the)142 485 R F0($j)2.928 E F1 .429
+(macro as speci\214ed by RFC821.)2.928 F(Def)5.429 E .429
+(aults to \231$j Sendmail $v ready at $b\232.)-.1 F 2.313
+(Commonly rede\214ned to include the con\214guration v)142 497 R 2.313
+(ersion number)-.15 F 4.813(,e)-.4 G 2.313(.g., \231$j Sendmail)431.874 497 R
+($v/$Z ready at $b\232)142 509 Q($f)117 525.2 Q F0(The sender \(fr)142 525.2 Q
+(om\) addr)-.18 E(ess.)-.18 E F1($g)117 541.4 Q F0(The sender addr)142 541.4 Q
+(ess r)-.18 E(elati)-.18 E .2 -.1(ve t)-.1 H 2.5(ot).1 G(he r)275.59 541.4 Q
+(ecipient.)-.18 E F1($h)117 557.6 Q F0(The r)142 557.6 Q(ecipient host.)-.18 E
+F1($i)117 573.8 Q F0(The queue id.)142 573.8 Q F1($j\210)117 590 Q F0 .557
+(The \231of\214cial\232 domain name f)142 590 R .557(or this site.)-.25 F F1
+.557(This is fully quali\214ed if the full quali\214cation)5.557 F .137
+(can be found.)142 602 R(It)5.137 E F2(must)2.637 E F1 .136
+(be rede\214ned to be the fully quali\214ed domain name if your system is)2.637
+F(not con\214gured so that information can \214nd it automatically)142 614 Q(.)
+-.65 E($k)117 630.2 Q F0(The UUCP node name \(fr)142 630.2 Q
+(om the uname system call\).)-.18 E F1($l\207)117 646.4 Q F0 .972(The f)142
+646.4 R .972(ormat of the UNIX fr)-.25 F .972(om line.)-.18 F F1 .972
+(Unless you ha)5.972 F 1.272 -.15(ve c)-.2 H .972(hanged the UNIX mailbox for)
+.15 F(-)-.2 E(mat, you should not change the def)142 658.4 Q
+(ault, which is \231From $g)-.1 E($d\232.)5 E .32 LW 76 678.8 72 678.8 DL 80
+678.8 76 678.8 DL 84 678.8 80 678.8 DL 88 678.8 84 678.8 DL 92 678.8 88 678.8
+DL 96 678.8 92 678.8 DL 100 678.8 96 678.8 DL 104 678.8 100 678.8 DL 108 678.8
+104 678.8 DL 112 678.8 108 678.8 DL 116 678.8 112 678.8 DL 120 678.8 116 678.8
+DL 124 678.8 120 678.8 DL 128 678.8 124 678.8 DL 132 678.8 128 678.8 DL 136
+678.8 132 678.8 DL 140 678.8 136 678.8 DL 144 678.8 140 678.8 DL 148 678.8 144
+678.8 DL 152 678.8 148 678.8 DL 156 678.8 152 678.8 DL 160 678.8 156 678.8 DL
+164 678.8 160 678.8 DL 168 678.8 164 678.8 DL 172 678.8 168 678.8 DL 176 678.8
+172 678.8 DL 180 678.8 176 678.8 DL 184 678.8 180 678.8 DL 188 678.8 184 678.8
+DL 192 678.8 188 678.8 DL 196 678.8 192 678.8 DL 200 678.8 196 678.8 DL 204
+678.8 200 678.8 DL 208 678.8 204 678.8 DL 212 678.8 208 678.8 DL 216 678.8 212
+678.8 DL/F4 5/Times-Roman@0 SF(10)93.6 689.2 Q/F5 8/Times-Roman@0 SF(As of v)
+3.2 I(ersion 8.6, all of these macros ha)-.12 E .24 -.12(ve r)-.16 H
+(easonable def).12 E 2(aults. Pre)-.08 F(vious v)-.2 E
+(ersions required that the)-.12 E 2(yb)-.12 G 2(ed)424.728 692.4 S(e\214ned.)
+434.28 692.4 Q EP
+%%Page: 29 24
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-29)452.9 60 Q/F1 10/Times-Roman@0 SF($m)117 96 Q F0 .84
+(The domain part of the)142 96 R/F2 10/Times-Italic@0 SF -.1(ge)3.339 G
+(thostname).1 E F0 -.18(re)3.339 G(tur).18 E 3.339(nv)-.15 G(alue.)337.055 96 Q
+F1 .839(Under normal circumstances,)5.839 F F0($j)3.339 E F1(is)3.339 E(equi)
+142 108 Q -.25(va)-.25 G(lent to).25 E F0($w)2.5 E(.$m)-.7 E F1(.)A($n\207)117
+124.2 Q F0(The name of the daemon \(f)142 124.2 Q(or err)-.25 E(or messages\).)
+-.18 E F1(Def)5 E(aults to \231MAILER-D)-.1 E(AEMON\232.)-.4 E($o\207)117 140.4
+Q F0 2.03(The set of \231operators\232 in addr)142 140.4 R(esses.)-.18 E F1
+4.531(Al)7.031 G 2.031(ist of characters which will be considered)325.744 140.4
+R(tok)142 152.4 Q .537(ens and which will separate tok)-.1 F .537
+(ens when doing parsing.)-.1 F -.15(Fo)5.537 G 3.037(re).15 G .537
+(xample, if \231@\232 were in)408.502 152.4 R(the)142 164.4 Q F0($o)2.898 E F1
+.398(macro, then the input \231a@b\232 w)2.898 F .398
+(ould be scanned as three tok)-.1 F .398(ens: \231a,)-.1 F 2.898<9a99>-.7 G(@,)
+453.032 164.4 Q 2.899<9a61>-.7 G .399(nd \231b)475.821 164.4 R -.7<2e9a>-.4 G
+(Def)142 176.4 Q .436(aults to \231.:@[]\232, which is the minimum set necessa\
+ry to do RFC 822 parsing; a richer)-.1 F 1.715
+(set of operators is \231.:%@!/[]\232, which adds support for UUCP)142 188.4 R
+4.216(,t)-1.11 G 1.716(he %-hack, and X.400)409.712 188.4 R(addresses.)142
+200.4 Q($p)117 216.6 Q F0(Sendmail')142 216.6 Q 2.5(sp)-.37 G -.18(ro)196.92
+216.6 S(cess id.).18 E F1($q\207)117 232.8 Q F0 2.358(Default f)142 232.8 R
+2.358(ormat of sender addr)-.25 F(ess.)-.18 E F1(The)7.358 E F0($q)4.858 E F1
+2.357(macro speci\214es ho)4.857 F 4.857(wa)-.25 G 4.857(na)432.626 232.8 S
+2.357(ddress should)446.923 232.8 R .625(appear in a message when it is def)142
+244.8 R 3.126(aulted. Def)-.1 F .626(aults to \231<$g>\232.)-.1 F .626
+(It is commonly rede\214ned)5.626 F .183(to be \231$?x$x <$g>$|$g$.)142 256.8 R
+5.183<9a6f>-.7 G 2.683<7299>255.852 256.8 S .183($g$?x \($x\)$.)266.305 256.8 R
+.182(\232, corresponding to the follo)-.7 F .182(wing tw)-.25 F 2.682(of)-.1 G
+(ormats:)474 256.8 Q(Eric Allman <eric@CS.Berk)182 273 Q(ele)-.1 E -.65(y.)-.15
+G(EDU>).65 E(eric@CS.Berk)182 285 Q(ele)-.1 E -.65(y.)-.15 G
+(EDU \(Eric Allman\)).65 E F2(Sendmail)142 301.2 Q F1
+(properly quotes names that ha)2.5 E .3 -.15(ve s)-.2 H
+(pecial characters if the \214rst form is used.).15 E($r)117 317.4 Q F0(Pr)142
+317.4 Q(otocol used to r)-.18 E(ecei)-.18 E .2 -.1(ve t)-.1 H(he message.).1 E
+F1($s)117 333.6 Q F0(Sender')142 333.6 Q 2.5(sh)-.37 G(ost name.)186.91 333.6 Q
+F1($t)117 349.8 Q F0 2.5(An)142 349.8 S(umeric r)157.28 349.8 Q(epr)-.18 E
+(esentation of the curr)-.18 E(ent time.)-.18 E F1($u)117 366 Q F0(The r)142
+366 Q(ecipient user)-.18 E(.)-1 E F1($v)117 382.2 Q F0(The v)142 382.2 Q
+(ersion number of)-.1 E F2(sendmail)2.5 E F0(.)A F1($w\210)117 398.4 Q F0
+(The hostname of this site.)7.78 E F1(The)142 414.6 Q F0($w)2.5 E F1
+(macro is set to the root name of this host \(b)2.5 E(ut see belo)-.2 E 2.5(wf)
+-.25 G(or ca)403.46 414.6 Q -.15(ve)-.2 G(ats\).).15 E($x)117 430.8 Q F0
+(The full name of the sender)142 430.8 Q(.)-1 E F1($z)117 447 Q F0
+(The home dir)142 447 Q(ectory of the r)-.18 E(ecipient.)-.18 E F1($_)117 463.2
+Q F0(The v)142 463.2 Q(alidated sender addr)-.1 E(ess.)-.18 E F1 .918
+(There are three types of dates that can be used.)142 479.4 R(The)5.918 E F0
+($a)3.418 E F1(and)3.418 E F0($b)3.418 E F1 .918(macros are in RFC 822)3.418 F
+(format;)117 491.4 Q F0($a)3.047 E F1 .547(is the time as e)3.047 F .547
+(xtracted from the \231Date:\232 line of the message \(if there w)-.15 F .546
+(as one\), and)-.1 F F0($b)117 503.4 Q F1 .145
+(is the current date and time \(used for postmarks\).)2.645 F .145
+(If no \231Date:\232 line is found in the incoming)5.145 F(message,)117 515.4 Q
+F0($a)2.547 E F1 .047(is set to the current time also.)2.547 F(The)5.046 E F0
+($d)2.546 E F1 .046(macro is equi)2.546 F -.25(va)-.25 G .046(lent to the).25 F
+F0($b)2.546 E F1 .046(macro in UNIX)2.546 F(\(ctime\) format.)117 527.4 Q .606
+(The macros)142 543.6 R F0($w)3.106 E F1(,)A F0($j)3.106 E F1 3.106(,a)C(nd)
+228.844 543.6 Q F0($m)3.106 E F1 .607(are set to the identity of this host.)
+3.106 F F2(Sendmail)5.607 E F1 .607(tries to \214nd the)3.107 F .025(fully qua\
+li\214ed name of the host if at all possible; it does this by calling)117 555.6
+R F2 -.1(ge)2.525 G(thostname).1 E F1 .025(\(2\) to get the)B 1.511
+(current hostname and then passing that to)117 567.6 R F2 -.1(ge)4.012 G
+(thostbyname).1 E F1 1.512(\(3\) which is supposed to return the)B .185
+(canonical v)117 581.6 R .185(ersion of that host name.)-.15 F/F3 7
+/Times-Roman@0 SF(11)262.195 577.6 Q F1 .184(Assuming this is successful,)
+271.88 581.6 R F0($j)2.684 E F1 .184(is set to the fully quali\214ed)2.684 F
+1.463(name and)117 593.6 R F0($m)3.963 E F1 1.464
+(is set to the domain part of the name \(e)3.964 F -.15(ve)-.25 G 1.464
+(rything after the \214rst dot\).).15 F(The)6.464 E F0($w)3.964 E F1 .166
+(macro is set to the \214rst w)117 605.6 R .166(ord \(e)-.1 F -.15(ve)-.25 G
+.166(rything before the \214rst dot\) if you ha).15 F .466 -.15(ve a l)-.2 H
+-2.15 -.25(ev e).15 H 2.666(l5o).25 G 2.666(rh)452.018 605.6 S .166(igher con-)
+463.014 605.6 R .183(\214guration \214le; otherwise, it is set to the same v)
+117 617.6 R .184(alue as)-.25 F F0($j)2.684 E F1 5.184(.I)C 2.684(ft)355.32
+617.6 S .184(he canoni\214cation is not successful,)364.114 617.6 R
+(it is imperati)117 631.6 Q .3 -.15(ve t)-.25 H(hat the con\214g \214le set).15
+E F0($j)2.5 E F1(to the fully quali\214ed domain name)2.5 E F3(12)416.59 627.6
+Q F1(.)423.59 631.6 Q(The)142 647.8 Q F0($f)3.115 E F1 .614(macro is the id of\
+ the sender as originally determined; when mailing to a speci\214c)3.115 F .601
+(host the)117 659.8 R F0($g)3.101 E F1 .601
+(macro is set to the address of the sender)3.101 F F2 -.37(re)3.102 G .602
+(lative to the r).37 F(ecipient.)-.37 E F1 -.15(Fo)5.602 G 3.102(re).15 G .602
+(xample, if I)456.416 659.8 R .32 LW 76 669.4 72 669.4 DL 80 669.4 76 669.4 DL
+84 669.4 80 669.4 DL 88 669.4 84 669.4 DL 92 669.4 88 669.4 DL 96 669.4 92
+669.4 DL 100 669.4 96 669.4 DL 104 669.4 100 669.4 DL 108 669.4 104 669.4 DL
+112 669.4 108 669.4 DL 116 669.4 112 669.4 DL 120 669.4 116 669.4 DL 124 669.4
+120 669.4 DL 128 669.4 124 669.4 DL 132 669.4 128 669.4 DL 136 669.4 132 669.4
+DL 140 669.4 136 669.4 DL 144 669.4 140 669.4 DL 148 669.4 144 669.4 DL 152
+669.4 148 669.4 DL 156 669.4 152 669.4 DL 160 669.4 156 669.4 DL 164 669.4 160
+669.4 DL 168 669.4 164 669.4 DL 172 669.4 168 669.4 DL 176 669.4 172 669.4 DL
+180 669.4 176 669.4 DL 184 669.4 180 669.4 DL 188 669.4 184 669.4 DL 192 669.4
+188 669.4 DL 196 669.4 192 669.4 DL 200 669.4 196 669.4 DL 204 669.4 200 669.4
+DL 208 669.4 204 669.4 DL 212 669.4 208 669.4 DL 216 669.4 212 669.4 DL/F4 5
+/Times-Roman@0 SF(11)93.6 679.8 Q/F5 8/Times-Roman@0 SF -.12(Fo)3.2 K 2(re).12
+G(xample, on some systems)115.024 683 Q/F6 8/Times-Italic@0 SF -.08(ge)2 G
+(thostname).08 E F5(might return \231foo\232 which w)2 E
+(ould be mapped to \231foo.bar)-.08 E(.com\232 by)-.44 E F6 -.08(ge)2 G
+(thostbyname).08 E F5(.)A F4(12)93.6 693.4 Q F5(Older v)3.2 I
+(ersions of sendmail didn')-.12 E 2(tp)-.144 G(re-de\214ne)211.88 696.6 Q/F7 8
+/Times-Bold@0 SF($j)2 E F5(at all, so up until 8.6, con\214g \214les)2 E F6
+(always)2 E F5(had to de\214ne)2 E F7($j)2 E F5(.)A EP
+%%Page: 30 25
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-30 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 1.65
+(send to \231bollard@matisse.CS.Berk)117 96 R(ele)-.1 E -.65(y.)-.15 G 1.65
+(EDU\232 from the machine \231v).65 F(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)
+-.15 G(EDU\232).65 E(the)117 108 Q F0($f)2.5 E F1
+(macro will be \231eric\232 and the)2.5 E F0($g)2.5 E F1
+(macro will be \231eric@v)2.5 E(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G
+(EDU.).65 E<9a>-.7 E(The)142 124.2 Q F0($x)3.837 E F1 1.338
+(macro is set to the full name of the sender)3.837 F 6.338(.T)-.55 G 1.338
+(his can be determined in se)369.13 124.2 R -.15(ve)-.25 G(ral).15 E -.1(wa)117
+136.2 S 2.953(ys. It).1 F .453(can be passed as \215ag to)2.953 F/F2 10
+/Times-Italic@0 SF(sendmail)2.953 E F1 5.453(.T)C .453
+(he second choice is the v)303.447 136.2 R .453(alue of the \231Full-name:\232)
+-.25 F .512(line in the header if it e)117 148.2 R .513
+(xists, and the third choice is the comment \214eld of a \231From:\232 line.)
+-.15 F .513(If all)5.513 F 1.149(of these f)117 160.2 R 1.149
+(ail, and if the message is being originated locally)-.1 F 3.648(,t)-.65 G
+1.148(he full name is look)369.684 160.2 R 1.148(ed up in the)-.1 F F2
+(/etc/passwd)117 172.2 Q F1(\214le.)2.5 E .438(When sending, the)142 188.4 R F0
+($h)2.938 E F1(,)A F0($u)2.938 E F1 2.938(,a)C(nd)256.96 188.4 Q F0($z)2.938 E
+F1 .438(macros get set to the host, user)2.938 F 2.939(,a)-.4 G .439
+(nd home directory \(if)417.423 188.4 R 1.455(local\) of the recipient.)117
+200.4 R 1.455(The \214rst tw)6.455 F 3.955(oa)-.1 G 1.454(re set from the)
+278.445 200.4 R F0($@)3.954 E F1(and)3.954 E F0($:)3.954 E F1 1.454
+(part of the re)3.954 F 1.454(writing rules,)-.25 F(respecti)117 212.4 Q -.15
+(ve)-.25 G(ly).15 E(.)-.65 E(The)142 228.6 Q F0($p)2.806 E F1(and)2.806 E F0
+($t)2.806 E F1 .306(macros are used to create unique strings \(e.g., for the \
+\231Message-Id:\232 \214eld\).)2.806 F(The)117 240.6 Q F0($i)2.538 E F1 .037(m\
+acro is set to the queue id on this host; if put into the timestamp line it ca\
+n be e)2.538 F(xtremely)-.15 E .407(useful for tracking messages.)117 252.6 R
+(The)5.407 E F0($v)2.907 E F1 .407(macro is set to be the v)2.907 F .407
+(ersion number of)-.15 F F2(sendmail)2.907 E F1 2.907(;t)C .408(his is)482.752
+252.6 R(normally put in timestamps and has been pro)117 264.6 Q -.15(ve)-.15 G
+2.5(ne).15 G(xtremely useful for deb)317.64 264.6 Q(ugging.)-.2 E(The)142 280.8
+Q F0($c)2.715 E F1 .215(\214eld is set to the \231hop count,)2.715 F 2.714
+<9a69>-.7 G .214(.e., the number of times this message has been pro-)297.664
+280.8 R 3.183(cessed. This)117 292.8 R .683(can be determined by the)3.183 F F0
+<ad68>3.183 E F1 .684(\215ag on the command line or by counting the times-)
+3.183 F(tamps in the message.)117 304.8 Q(The)142 321 Q F0($r)3.427 E F1(and)
+3.427 E F0($s)3.427 E F1 .926
+(\214elds are set to the protocol used to communicate with)3.427 F F2(sendmail)
+3.426 E F1 .926(and the)3.426 F(sending hostname.)117 333 Q(The)142 349.2 Q F0
+($_)2.72 E F1 .22(is set to a v)2.72 F .22(alidated sender host name.)-.25 F
+.22(If the sender is running an RFC 1413 com-)5.22 F(pliant IDENT serv)117
+361.2 Q(er)-.15 E 2.5(,i)-.4 G 2.5(tw)206.43 361.2 S
+(ill include the user name on that host.)218.93 361.2 Q F0 2.5(5.1.3. C)102
+385.2 R(and F \212 de\214ne classes)2.5 E F1 .197
+(Classes of phrases may be de\214ned to match on the left hand side of re)142
+401.4 R .196(writing rules, where)-.25 F 2.79<6199>117 413.4 S .291
+(phrase\232 is a sequence of characters that do not contain space characters.)
+128.67 413.4 R -.15(Fo)5.291 G 2.791(re).15 G .291(xample a class)445.098 413.4
+R .356(of all local names for this site might be created so that attempts to s\
+end to oneself can be elimi-)117 425.4 R 2.89(nated. These)117 437.4 R .39(can\
+ either be de\214ned directly in the con\214guration \214le or read in from an\
+other \214le.)2.89 F .797(Classes may be gi)117 449.4 R -.15(ve)-.25 G 3.297
+(nn).15 G .796(ames from the set of upper case letters.)213.668 449.4 R(Lo)
+5.796 E .796(wer case letters and special)-.25 F(characters are reserv)117
+461.4 Q(ed for system use.)-.15 E(The syntax is:)142 477.6 Q F0(C)157 493.8 Q
+F2 1.666(cp)C(hr)-1.666 E(ase1 phr)-.15 E(ase2...)-.15 E F0(F)157 505.8 Q F2
+1.666<638c>C(le)-1.666 E F1 1.114(The \214rst form de\214nes the class)117 522
+R F2(c)3.614 E F1 1.114(to match an)3.614 F 3.614(yo)-.15 G 3.615(ft)319.63 522
+S 1.115(he named w)329.355 522 R 3.615(ords. It)-.1 F 1.115
+(is permissible to split)3.615 F(them among multiple lines; for e)117 534 Q
+(xample, the tw)-.15 E 2.5(of)-.1 G(orms:)317.57 534 Q(CHmonet ucbmonet)157
+550.2 Q(and)117 566.4 Q(CHmonet)157 582.6 Q(CHucbmonet)157 594.6 Q(are equi)117
+610.8 Q -.25(va)-.25 G 2.5(lent. The).25 F
+(second form reads the elements of the class)2.5 E F2(c)2.5 E F1
+(from the named)2.5 E F2(\214le)2.5 E F1(.)A(The)142 627 Q F0($~)3.113 E F1
+.613(\(match entries not in class\) only matches a single w)3.113 F .612
+(ord; multi-w)-.1 F .612(ord entries in the)-.1 F
+(class are ignored in this conte)117 639 Q(xt.)-.15 E .383(The class)142 655.2
+R F0($=w)2.883 E F1 .384(is set to be the set of all names this host is kno)
+2.883 F .384(wn by)-.25 F 5.384(.T)-.65 G .384(his can be used to)431.364 655.2
+R(match local hostnames.)117 667.2 Q(The class)142 683.4 Q F0($=k)2.5 E F1
+(is set to be the same as)2.5 E F0($k)2.5 E F1 2.5(,t)C
+(hat is, the UUCP node name.)312.69 683.4 Q(The class)142 699.6 Q F0($=m)2.5 E
+F1(is set to the set of domains by which this host is kno)2.5 E
+(wn, initially just)-.25 E F0($m)2.5 E F1(.)A EP
+%%Page: 31 26
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-31)452.9 60 Q/F1 10/Times-Italic@0 SF(Sendmail)142 96 Q/F2 10
+/Times-Roman@0 SF .543(can be compiled to allo)3.043 F 3.043(wa)-.25 G F1
+(scanf)-.001 E F2 .542(\(3\) string on the)B F0(F)3.042 E F2 3.042(line. This)
+3.042 F .542(lets you do sim-)3.042 F .519(plistic parsing of te)117 108 R .519
+(xt \214les.)-.15 F -.15(Fo)5.519 G 3.019(re).15 G .52
+(xample, to read all the user names in your system)251.884 108 R F1
+(/etc/passwd)3.02 E F2(\214le into a class, use)117 120 Q(FL/etc/passwd %[^:])
+157 136.2 Q(which reads e)117 152.4 Q -.15(ve)-.25 G
+(ry line up to the \214rst colon.).15 E F0 2.5(5.1.4. M)102 176.4 R 2.5<8a64>
+2.5 G(e\214ne mailer)159.5 176.4 Q F2(Programs and interf)142 192.6 Q
+(aces to mailers are de\214ned in this line.)-.1 E(The format is:)5 E F0(M)157
+208.8 Q F1(name)A F2 2.5(,{)C F1(\214eld)197.9 208.8 Q F2(=)A F1(value)A F2(}*)
+1.666 E(where)117 225 Q F1(name)3.244 E F2 .744(is the name of the mailer \(us\
+ed internally only\) and the \231\214eld=name\232 pairs de\214ne)3.244 F
+(attrib)117 237 Q(utes of the mailer)-.2 E 5(.F)-.55 G(ields are:)220.13 237 Q
+-.15(Pa)157 253.2 S 51.87(th The).15 F(pathname of the mailer)2.5 E 47.83
+(Flags Special)157 265.2 R(\215ags for this mailer)2.5 E 41.73(Sender A)157
+277.2 R(re)2.5 E(writing set for sender addresses)-.25 E 31.17(Recipient A)157
+289.2 R(re)2.5 E(writing set for recipient addresses)-.25 E(Ar)157 301.2 Q
+49.13(gv An)-.18 F(ar)2.5 E(gument v)-.18 E(ector to pass to this mailer)-.15 E
+55.61(Eol The)157 313.2 R(end-of-line string for this mailer)2.5 E 35.62
+(Maxsize The)157 325.2 R(maximum message length to this mailer)2.5 E 32.27
+(Linelimit The)157 337.2 R(maximum line length in the message body)2.5 E 31.18
+(Directory The)157 349.2 R -.1(wo)2.5 G(rking directory for the mailer).1 E
+(Only the \214rst character of the \214eld name is check)117 365.4 Q(ed.)-.1 E
+1.144(The follo)142 381.6 R 1.144
+(wing \215ags may be set in the mailer description.)-.25 F(An)6.144 E 3.644(yo)
+-.15 G 1.144(ther \215ags may be used)409.994 381.6 R(freely to conditionally \
+assign headers to messages destined for particular mailers.)117 393.6 Q 15.56
+(aR)117 409.8 S(un Extended SMTP \(ESMTP\) protocol \(de\214ned in RFCs 1425, \
+1426, and 1427\).)143.67 409.8 Q 15(bF)117 426 S .674
+(orce a blank line on the end of a message.)142.41 426 R .674
+(This is intended to w)5.674 F .674(ork around some stupid)-.1 F -.15(ve)137
+438 S .851(rsions of /bin/mail that require a blank line, b).15 F .851
+(ut do not pro)-.2 F .852(vide it themselv)-.15 F 3.352(es. It)-.15 F -.1(wo)
+3.352 G(uld).1 E(not normally be used on netw)137 450 Q(ork mail.)-.1 E 15.56
+(cD)117 466.2 S 4.166(on)144.22 466.2 S 1.666
+(ot include comments in addresses.)158.386 466.2 R 1.665
+(This should only be used if you ha)6.665 F 1.965 -.15(ve t)-.2 H 4.165(ow).15
+G(ork)490.67 466.2 Q(around a remote mailer that gets confused by comments.)137
+478.2 Q 13.33(CI)117 494.4 S 3.06(fm)140.33 494.4 S .56(ail is)154.5 494.4 R F1
+-.37(re)3.06 G(ceived).37 E F2 .56(from a mailer with this \215ag set, an)3.06
+F 3.06(ya)-.15 G .56(ddresses in the header that do not)367.33 494.4 R(ha)137
+506.4 Q .331 -.15(ve a)-.2 H 2.531(na).15 G 2.531(ts)174.472 506.4 S .031
+(ign \(\231@\232\) after being re)183.673 506.4 R .031
+(written by ruleset three will ha)-.25 F .33 -.15(ve t)-.2 H .03
+(he \231@domain\232 clause).15 F(from the sender tack)137 518.4 Q(ed on.)-.1 E
+(This allo)5 E(ws mail with headers of the form:)-.25 E(From: usera@hosta)177
+534.6 Q -.8(To)177 546.6 S 2.5(:u).8 G(serb@hostb, userc)197.59 546.6 Q
+(to be re)137 562.8 Q(written as:)-.25 E(From: usera@hosta)177 579 Q -.8(To)177
+591 S 2.5(:u).8 G(serb@hostb, userc@hosta)197.59 591 Q(automatically)137 607.2
+Q(.)-.65 E 12.78(DT)117 623.4 S(his mailer w)143.11 623.4 Q
+(ants a \231Date:\232 header line.)-.1 E 15.56(eT)117 639.6 S .562
+(his mailer is e)143.11 639.6 R(xpensi)-.15 E .862 -.15(ve t)-.25 H 3.062(oc)
+.15 G .562(onnect to, so try to a)253.97 639.6 R -.2(vo)-.2 G .562
+(id connecting normally; an).2 F 3.063(yn)-.15 G(ecessary)470.13 639.6 Q
+(connection will occur during a queue run.)137 651.6 Q 13.89(EE)117 667.8 S
+(scape lines be)143.11 667.8 Q
+(ginning with \231From\232 in the message with a `>' sign.)-.15 E 16.67(fT)117
+684 S .969(he mailer w)143.11 684 R .969(ants a)-.1 F F0<ad66>3.469 E F1(fr)
+3.469 E(om)-.45 E F2 .969(\215ag, b)3.469 F .969(ut only if this is a netw)-.2
+F .969(ork forw)-.1 F .968(ard operation \(i.e., the)-.1 F(mailer will gi)137
+696 Q .3 -.15(ve a)-.25 H 2.5(ne).15 G(rror if the e)218.81 696 Q -.15(xe)-.15
+G(cuting user does not ha).15 E .3 -.15(ve s)-.2 H(pecial permissions\).).15 E
+14.44(FT)117 712.2 S(his mailer w)143.11 712.2 Q
+(ants a \231From:\232 header line.)-.1 E EP
+%%Page: 32 27
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-32 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 15(gN)117 96 S
+(ormally)144.22 96 Q(,)-.65 E/F2 10/Times-Italic@0 SF(sendmail)3.529 E F1 1.029
+(sends internally generated email \(e.g., error messages\) using the null)3.529
+F 1.767(return address)137 110 R/F3 7/Times-Roman@0 SF(13)195.137 106 Q F1
+1.766(as required by RFC 1123.)206.404 110 R(Ho)6.766 E(we)-.25 E -.15(ve)-.25
+G 2.566 -.4(r, s).15 H 1.766(ome mailers don').4 F 4.266(ta)-.18 G 1.766
+(ccept a null)454.368 110 R .922(return address.)137 122 R .922(If necessary)
+5.922 F 3.422(,y)-.65 G .922(ou can set the)261.938 122 R F0(g)3.422 E F1 .922
+(\215ag to pre)3.422 F -.15(ve)-.25 G(nt).15 E F2(sendmail)3.422 E F1 .922
+(from obe)3.422 F .922(ying the)-.15 F .212
+(standards; error messages will be sent as from the MAILER-D)137 134 R .211
+(AEMON \(actually)-.4 F 2.711(,t)-.65 G .211(he v)470.439 134 R(alue)-.25 E
+(of the)137 146 Q F0($n)2.5 E F1(macro\).)2.5 E 15(hU)117 162.2 S
+(pper case should be preserv)144.22 162.2 Q(ed in host names for this mailer)
+-.15 E(.)-.55 E 16.67(IT)117 178.4 S .092
+(his mailer will be speaking SMTP to another)143.11 178.4 R F2(sendmail)2.592 E
+F1 2.593<8a61>2.593 G 2.593(ss)381.242 178.4 S .093
+(uch it can use special proto-)391.615 178.4 R .319(col features.)137 190.4 R
+.319(This option is not required \(i.e., if this option is omitted the transmi\
+ssion will)5.319 F(still operate successfully)137 202.4 Q 2.5(,a)-.65 G
+(lthough perhaps not as ef)244.11 202.4 Q(\214ciently as possible\).)-.25 E
+17.22(lT)117 218.6 S(his mailer is local \(i.e., \214nal deli)143.11 218.6 Q
+-.15(ve)-.25 G(ry will be performed\).).15 E 13.89(LL)117 234.8 S .69
+(imit the line lengths as speci\214ed in RFC821.)143.11 234.8 R .69
+(This deprecated option should be replaced)5.69 F(by the)137 246.8 Q F0(L=)2.5
+E F1(mail declaration.)2.5 E -.15(Fo)5 G 2.5(rh).15 G(istoric reasons, the)
+272.54 246.8 Q F0(L)2.5 E F1(\215ag also sets the)2.5 E F0(7)2.5 E F1(\215ag.)
+2.5 E 12.22(mT)117 263 S 1.273
+(his mailer can send to multiple users on the same host in one transaction.)
+143.11 263 R 1.273(When a)6.273 F F0($u)3.773 E F1 .621(macro occurs in the)137
+275 R F2(ar)3.121 E(gv)-.37 E F1 .621
+(part of the mailer de\214nition, that \214eld will be repeated as neces-)3.121
+F(sary for all qualifying users.)137 287 Q 11.11(MT)117 303.2 S(his mailer w)
+143.11 303.2 Q(ants a \231Message-Id:\232 header line.)-.1 E 15(nD)117 319.4 S
+2.5(on)144.22 319.4 S
+(ot insert a UNIX-style \231From\232 line on the front of the message.)156.72
+319.4 Q 15(pU)117 335.6 S .702(se the route-addr style re)144.22 335.6 R -.15
+(ve)-.25 G .702(rse-path in the SMTP \231MAIL FR).15 F .701
+(OM:\232 command rather than)-.4 F .421
+(just the return address; although this is required in RFC821 section 3.1, man)
+137 347.6 R 2.922(yh)-.15 G .422(osts do not)459.816 347.6 R(process re)137
+359.6 Q -.15(ve)-.25 G(rse-paths properly).15 E 5(.R)-.65 G -2.15 -.25(ev e)
+272.3 359.6 T(rse-paths are of).25 E(\214cially discouraged by RFC 1123.)-.25 E
+14.44(PT)117 375.8 S(his mailer w)143.11 375.8 Q(ants a \231Return-P)-.1 E
+(ath:\232 line.)-.15 E 16.67(rS)117 392 S(ame as)142.56 392 Q F0(f)2.5 E F1 2.5
+(,b)C(ut sends a)185.68 392 Q F0<ad72>2.5 E F1(\215ag.)2.5 E 16.11(sS)117 408.2
+S(trip quote characters of)142.56 408.2 Q 2.5(fo)-.25 G 2.5(ft)245.61 408.2 S
+(he address before calling the mailer)254.22 408.2 Q(.)-.55 E 14.44(SD)117
+424.4 S(on')144.22 424.4 Q 3.443(tr)-.18 G .943
+(eset the userid before calling the mailer)166.923 424.4 R 5.943(.T)-.55 G .943
+(his w)344.324 424.4 R .942(ould be used in a secure en)-.1 F(viron-)-.4 E .49
+(ment where)137 436.4 R F2(sendmail)2.99 E F1 .49(ran as root.)2.99 F .491
+(This could be used to a)5.491 F -.2(vo)-.2 G .491(id for).2 F .491
+(ged addresses.)-.18 F .491(This \215ag)5.491 F(is suppressed if gi)137 448.4 Q
+-.15(ve)-.25 G 2.5(nf).15 G(rom an \231unsafe\232 en)228.81 448.4 Q
+(vironment \(e.g, a user')-.4 E 2.5(sm)-.55 G(ail.cf \214le\).)410.31 448.4 Q
+15(uU)117 464.6 S(pper case should be preserv)144.22 464.6 Q
+(ed in user names for this mailer)-.15 E(.)-.55 E 12.78(UT)117 480.8 S 2.997
+(his mailer w)143.11 480.8 R 2.996
+(ants Unix-style \231From\232 lines with the ugly UUCP-style \231remote from)
+-.1 F(<host>\232 on the end.)137 492.8 Q 15(xT)117 509 S(his mailer w)143.11
+509 Q(ants a \231Full-Name:\232 header line.)-.1 E 12.78(XT)117 525.2 S 1.22
+(his mailer w)143.11 525.2 R 1.22
+(ant to use the hidden dot algorithm as speci\214ed in RFC821; basically)-.1 F
+3.72(,a)-.65 G -.15(ny)494.15 525.2 S .225(line be)137 537.2 R .225
+(ginning with a dot will ha)-.15 F .525 -.15(ve a)-.2 H 2.725(ne).15 G .224
+(xtra dot prepended \(to be stripped at the other end\).)296.47 537.2 R .525(T\
+his insures that lines in the message containing a dot will not terminate the \
+message pre-)137 549.2 R(maturely)137 561.2 Q(.)-.65 E 15(7S)117 577.4 S .351
+(trip all output to se)142.56 577.4 R -.15(ve)-.25 G 2.851(nb).15 G 2.851
+(its. This)241.416 577.4 R .351(is the def)2.851 F .351(ault if the)-.1 F F0(L)
+2.851 E F1 .351(\215ag is set.)2.851 F .351(Note that clearing this)5.351 F
+.377(option is not suf)137 589.4 R .378
+(\214cient to get full eight bit data passed through)-.25 F F2(sendmail)2.878 E
+F1 5.378(.I)C 2.878(ft)439.708 589.4 S(he)448.696 589.4 Q F0(7)2.878 E F1 .378
+(option is)2.878 F(set, this is essentially al)137 601.4 Q -.1(wa)-.1 G
+(ys set, since the eighth bit w).1 E(as stripped on input.)-.1 E 2.122(The mai\
+ler with the special name \231error\232 can be used to generate a user error)
+142 617.6 R 7.122(.T)-.55 G(he)494.56 617.6 Q .246
+(\(optional\) host \214eld is an e)117 629.6 R .247
+(xit status to be returned, and the user \214eld is a message to be printed.)
+-.15 F .337(The e)117 641.6 R .337(xit status may be numeric or one of the v)
+-.15 F .336(alues USA)-.25 F .336(GE, NOUSER, NOHOST)-.4 F 2.836(,U)-.74 G -.35
+(NA)465.4 641.6 S -1.35(VA)-1 G(IL-)1.35 E .828(ABLE, SOFTW)117 653.6 R .828
+(ARE, TEMPF)-1.2 F .828(AIL, PR)-.74 F -1.88 -.4(OT O)-.4 H .828
+(COL, or CONFIG to return the corresponding EX_).4 F -.15(ex)117 665.6 S
+(it code.).15 E -.15(Fo)5 G 2.5(re).15 G(xample, the entry:)181.26 665.6 Q .32
+LW 76 678.8 72 678.8 DL 80 678.8 76 678.8 DL 84 678.8 80 678.8 DL 88 678.8 84
+678.8 DL 92 678.8 88 678.8 DL 96 678.8 92 678.8 DL 100 678.8 96 678.8 DL 104
+678.8 100 678.8 DL 108 678.8 104 678.8 DL 112 678.8 108 678.8 DL 116 678.8 112
+678.8 DL 120 678.8 116 678.8 DL 124 678.8 120 678.8 DL 128 678.8 124 678.8 DL
+132 678.8 128 678.8 DL 136 678.8 132 678.8 DL 140 678.8 136 678.8 DL 144 678.8
+140 678.8 DL 148 678.8 144 678.8 DL 152 678.8 148 678.8 DL 156 678.8 152 678.8
+DL 160 678.8 156 678.8 DL 164 678.8 160 678.8 DL 168 678.8 164 678.8 DL 172
+678.8 168 678.8 DL 176 678.8 172 678.8 DL 180 678.8 176 678.8 DL 184 678.8 180
+678.8 DL 188 678.8 184 678.8 DL 192 678.8 188 678.8 DL 196 678.8 192 678.8 DL
+200 678.8 196 678.8 DL 204 678.8 200 678.8 DL 208 678.8 204 678.8 DL 212 678.8
+208 678.8 DL 216 678.8 212 678.8 DL/F4 5/Times-Roman@0 SF(13)93.6 689.2 Q/F5 8
+/Times-Roman@0 SF(Actually)3.2 I 2(,t)-.52 G(his only applies to SMTP)131.856
+692.4 Q 2(,w)-.888 G(hich uses the `)222.088 692.4 Q(`MAIL FR)-.592 E(OM:<>')
+-.32 E 2('c)-.592 G(ommand.)336.48 692.4 Q EP
+%%Page: 33 28
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-33)452.9 60 Q/F1 10/Times-Roman@0 SF($#error $@ NOHOST $: Host unkno)
+157 96 Q(wn in this domain)-.25 E .261(on the RHS of a rule will cause the spe\
+ci\214ed error to be generated and the \231Host unkno)117 112.2 R .261
+(wn\232 e)-.25 F(xit)-.15 E(status to be returned if the LHS matches.)117 124.2
+Q(This mailer is only functional in ruleset zero.)5 E 1.563
+(The mailer named \231local\232)142 140.4 R/F2 10/Times-Italic@0 SF(must)4.063
+E F1 1.564(be de\214ned in e)4.063 F -.15(ve)-.25 G 1.564
+(ry con\214guration \214le.).15 F 1.564(This is used to)6.564 F(deli)117 152.4
+Q -.15(ve)-.25 G 4.039(rl).15 G 1.539
+(ocal mail, and is treated specially in se)151.189 152.4 R -.15(ve)-.25 G 1.538
+(ral w).15 F 4.038(ays. Additionally)-.1 F 4.038(,t)-.65 G 1.538
+(hree other mailers)428.724 152.4 R 1.367(named \231prog\232, \231*\214le*\232\
+, and \231*include*\232 may be de\214ned to tune the deli)117 164.4 R -.15(ve)
+-.25 G 1.368(ry of messages to).15 F
+(programs, \214les, and :include: lists respecti)117 176.4 Q -.15(ve)-.25 G(ly)
+.15 E 5(.T)-.65 G(he)315.38 176.4 Q 2.5(yd)-.15 G(ef)337.17 176.4 Q(ault to:)
+-.1 E(Mprog, P=/bin/sh, F=lsD, A=sh \255c $u)157 192.6 Q(M*\214le*, P=/de)157
+204.6 Q(v/null, F=lsDFMPEu, A=FILE)-.25 E(M*include*, P=/de)157 216.6 Q
+(v/null, F=su, A=INCLUDE)-.25 E 1.264(The Sender and Recipient re)142 237 R
+1.263(writing sets may either be a simple inte)-.25 F 1.263(ger or may be tw)
+-.15 F(o)-.1 E(inte)117 249 Q .046
+(gers separated by a slash; if so, the \214rst re)-.15 F .047
+(writing set is applied to en)-.25 F -.15(ve)-.4 G .047(lope addresses and the)
+.15 F(second is applied to headers.)117 261 Q 1.259
+(The Directory is actually a colon-separated path of directories to try)142
+277.2 R 6.258(.F)-.65 G 1.258(or e)439.704 277.2 R 1.258(xample, the)-.15 F
+.143(de\214nition \231D=$z:/\232 \214rst tries to e)117 289.2 R -.15(xe)-.15 G
+.143(cute in the recipient').15 F 2.643(sh)-.55 G .144
+(ome directory; if that is not a)353.327 289.2 R -.25(va)-.2 G(ilable,).25 E
+.781(it tries to e)117 301.2 R -.15(xe)-.15 G .781
+(cute in the root of the \214lesystem.).15 F .78
+(This is intended to be used only on the \231prog\232)5.781 F(mailer)117 313.2
+Q 2.898(,s)-.4 G .398(ince some shells \(such as)151.438 313.2 R F2(csh)2.898 E
+F1 2.898(\)r)C .398(efuse to e)279.356 313.2 R -.15(xe)-.15 G .398(cute if the)
+.15 F 2.898(yc)-.15 G .398(annot read the home directory)380.586 313.2 R(.)-.65
+E .416(Since the queue directory is not normally readable by normal users)117
+325.2 R F2(csh)2.916 E F1 .416(scripts as recipients can)2.916 F -.1(fa)117
+337.2 S(il.).1 E F0 2.5(5.1.5. H)102 361.2 R 2.5<8a64>2.5 G(e\214ne header)
+157.84 361.2 Q F1 .198(The format of the header lines that)142 377.4 R F2
+(sendmail)2.698 E F1 .198(inserts into the message are de\214ned by the)2.698 F
+F0(H)2.699 E F1 2.5(line. The)117 389.4 R(syntax of this line is:)2.5 E F0(H)
+157 405.6 Q F1([)A F0(?)A F2(m\215a)A(gs)-.1 E F0(?)A F1(])A F2(hname)A F0(:)A
+F2(htemplate)2.5 E F1 .691(Continuation lines in this spec are re\215ected dir\
+ectly into the outgoing message.)117 421.8 R(The)5.69 E F2(htemplate)3.19 E F1
+1.566(is macro e)117 433.8 R 1.567(xpanded before insertion into the message.)
+-.15 F 1.567(If the)6.567 F F2(m\215a)4.067 E(gs)-.1 E F1 1.567
+(\(surrounded by question)4.067 F .219(marks\) are speci\214ed, at least one o\
+f the speci\214ed \215ags must be stated in the mailer de\214nition for)117
+445.8 R .093(this header to be automatically output.)117 457.8 R .093
+(If one of these headers is in the input it is re\215ected to the)5.093 F
+(output re)117 469.8 Q -.05(ga)-.15 G(rdless of these \215ags.).05 E
+(Some headers ha)142 486 Q .3 -.15(ve s)-.2 H
+(pecial semantics that will be described belo).15 E -.65(w.)-.25 G F0 2.5
+(5.1.6. O)102 510 R 2.5<8a73>2.5 G(et option)156.17 510 Q F1 .045(There are a \
+number of \231random\232 options that can be set from a con\214guration \214le\
+.)142 526.2 R(Options)5.045 E(are represented by single characters.)117 538.2 Q
+(The syntax of this line is:)5 E F0(O)157 554.4 Q F2 1.666(ov)C(alue)-1.666 E
+F1 1.054(This sets option)117 570.6 R F2(o)3.554 E F1 1.054(to be)3.554 F F2
+(value)3.554 E F1 6.054(.D)C 1.054(epending on the option,)256.318 570.6 R F2
+(value)3.555 E F1 1.055(may be a string, an inte)3.555 F(ger)-.15 E 3.555(,a)
+-.4 G(boolean \(with le)117 582.6 Q -.05(ga)-.15 G 2.5(lv).05 G
+(alues \231t\232, \231T\232, \231f\232, or \231F\232; the def)201.26 582.6 Q
+(ault is TR)-.1 E(UE\), or a time interv)-.4 E(al.)-.25 E
+(The options supported are:)142 598.8 Q(a)117 615 Q F2(N)A F1 .655(If set, w)
+189 615 R .655(ait up to)-.1 F F2(N)3.155 E F1 .655
+(minutes for an \231@:@\232 entry to e)3.155 F .655(xist in the alias database)
+-.15 F .474(before starting up.)189 627 R .474(If it does not appear in)5.474 F
+F2(N)2.974 E F1 .475(minutes, reb)2.974 F .475(uild the database \(if)-.2 F
+(the)189 639 Q F0(D)2.5 E F1(option is also set\) or issue a w)2.5 E(arning.)
+-.1 E(A)117 655.2 Q F2 .507(spec, spec, ...)B F1 .507
+(Specify possible alias \214le\(s\).)190.014 655.2 R(Each)5.507 E F2(spec)3.006
+E F1 .506(should be in the format `)3.006 F(`)-.74 E F2(class)A F0(:)A F2
+(\214le)3.006 E F1 -.74('')C(where)189 667.2 Q F2(class)3.049 E F0(:)A F1 .549
+(is optional and def)3.049 F .549(aults to `)-.1 F(`implicit')-.74 E 3.049
+('. Depending)-.74 F .549(on ho)3.049 F(w)-.25 E F2(send-)3.05 E(mail)189 679.2
+Q F1 1.335(is compiled, v)3.835 F 1.335
+(alid classes are \231implicit\232 \(search through a compiled-in)-.25 F .193
+(list of alias \214le types, for back compatibility\), \231hash\232 \(if)189
+691.2 R/F3 9/Times-Roman@0 SF(NEWDB)2.693 E F1 .193(is speci\214ed\),)2.693 F
+.882(\231dbm\232 \(if)189 703.2 R F3(NDBM)3.382 E F1 .882
+(is speci\214ed\), \231stab\232 \(internal symbol table \212 not normally)3.382
+F .475(used unless you ha)189 715.2 R .775 -.15(ve n)-.2 H 2.975(oo).15 G .476
+(ther database lookup\), or \231nis\232 \(if)295.735 715.2 R F3(NIS)2.976 E F1
+.476(is speci\214ed\).)2.976 F EP
+%%Page: 34 29
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-34 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(If a list of)189
+96 Q/F2 10/Times-Italic@0 SF(spec)2.5 E F1 2.5(sa)C(re pro)259.26 96 Q(vided,)
+-.15 E F2(sendmail)2.5 E F1(searches them in order)2.5 E(.)-.55 E(b)117 112.2 Q
+F2(N)A F1(/)A F2(M)A F1 1.589(Insist on at least)189 112.2 R F2(N)4.089 E F1
+1.588(blocks free on the \214lesystem that holds the queue \214les)4.089 F .19
+(before accepting email via SMTP)189 124.2 R 5.19(.I)-1.11 G 2.69(ft)334.09
+124.2 S .19(here is insuf)342.89 124.2 R .19(\214cient space)-.25 F F2
+(sendmail)2.69 E F1(gi)2.69 E -.15(ve)-.25 G(s).15 E 3.67(a4)189 136.2 S 1.17
+(52 response to the MAIL command.)202.11 136.2 R 1.17(This in)6.17 F 1.17
+(vites the sender to try ag)-.4 F(ain)-.05 E(later)189 148.2 Q 5.986(.T)-.55 G
+.986(he optional)220.816 148.2 R F2(M)3.486 E F1 .987
+(is a maximum message size adv)3.486 F .987(ertised in the ESMTP)-.15 F
+(EHLO response.)189 160.2 Q(It is currently otherwise unused.)5 E(B)117 176.4 Q
+F2(c)A F1 1.445(Set the blank substitution character to)189 176.4 R F2(c)3.945
+E F1 6.444(.U)C 1.444(nquoted spaces in addresses are)371.594 176.4 R
+(replaced by this character)189 188.4 Q 5(.D)-.55 G(ef)305.63 188.4 Q
+(aults to space \(i.e., no change is made\).)-.1 E 67.56(cI)117 204.6 S 3.892
+(fa)192.33 204.6 S 3.892(no)203.992 204.6 S 1.393(utgoing mailer is mark)
+217.884 204.6 R 1.393(ed as being e)-.1 F(xpensi)-.15 E -.15(ve)-.25 G 3.893
+(,d).15 G(on')415.294 204.6 Q 3.893(tc)-.18 G 1.393(onnect immedi-)439.557
+204.6 R(ately)189 216.6 Q 6.164(.T)-.65 G 1.164
+(his requires that queueing be compiled in, since it will depend on a)222.564
+216.6 R(queue run process to actually send the mail.)189 228.6 Q(C)117 244.8 Q
+F2(N)A F1 1.49(Checkpoints the queue e)189 244.8 R -.15(ve)-.25 G(ry).15 E F2
+(N)3.99 E F1(\(def)3.99 E 1.49(ault 10\) addresses sent.)-.1 F 1.49
+(If your system)6.49 F .785(crashes during deli)189 256.8 R -.15(ve)-.25 G .785
+(ry to a lar).15 F .785(ge list, this pre)-.18 F -.15(ve)-.25 G .785
+(nts retransmission to an).15 F 3.285(yb)-.15 G(ut)496.22 256.8 Q
+(the last recipients.)189 268.8 Q(d)117 285 Q F2(x)A F1(Deli)189 285 Q -.15(ve)
+-.25 G 2.5(ri).15 G 2.5(nm)223.87 285 S(ode)239.15 285 Q F2(x)2.5 E F1 5(.L)C
+-2.25 -.15(eg a)274.14 285 T 2.5(lm).15 G(odes are:)300.88 285 Q 17.22(iD)229
+301.2 S(eli)256.22 301.2 Q -.15(ve)-.25 G 2.5(ri).15 G(nteracti)283.87 301.2 Q
+-.15(ve)-.25 G(ly \(synchronously\)).15 E 15(bD)229 313.2 S(eli)256.22 313.2 Q
+-.15(ve)-.25 G 2.5(ri).15 G 2.5(nb)283.87 313.2 S(ackground \(asynchronously\))
+296.37 313.2 Q 15(qJ)229 325.2 S(ust queue the message \(deli)252.89 325.2 Q
+-.15(ve)-.25 G 2.5(rd).15 G(uring queue run\))382.74 325.2 Q(Def)189 341.4 Q
+1.32(aults to `)-.1 F(`b')-.74 E 3.82('i)-.74 G 3.82(fn)261.64 341.4 S 3.82(oo)
+273.79 341.4 S 1.32(ption is speci\214ed, `)287.61 341.4 R(`i')-.74 E 3.82('i)
+-.74 G 3.82(fi)385.57 341.4 S 3.82(ti)395.5 341.4 S 3.82(ss)404.88 341.4 S 1.32
+(peci\214ed b)416.48 341.4 R 1.32(ut gi)-.2 F -.15(ve)-.25 G 3.82(nn).15 G(o)
+499 341.4 Q(ar)189 353.4 Q(gument \(i.e., `)-.18 E(`Od')-.74 E 2.5('i)-.74 G
+2.5(se)278.98 353.4 S(qui)289.81 353.4 Q -.25(va)-.25 G(lent to `).25 E(`Odi')
+-.74 E('\).)-.74 E 64.78(DI)117 369.6 S 2.736(fs)192.33 369.6 S .236(et, reb)
+202.286 369.6 R .236(uild the alias database if necessary and possible.)-.2 F
+.235(If this option is not)5.236 F(set,)189 381.6 Q F2(sendmail)3.385 E F1 .885
+(will ne)3.385 F -.15(ve)-.25 G 3.385(rr).15 G(eb)292.96 381.6 Q .885
+(uild the alias database unless e)-.2 F .885(xplicitly requested)-.15 F(using)
+189 393.6 Q F0(\255bi)2.5 E F1(.)A(e)117 409.8 Q F2(x)A F1
+(Dispose of errors using mode)189 409.8 Q F2(x)2.5 E F1 5(.T)C(he v)327.31
+409.8 Q(alues for)-.25 E F2(x)2.5 E F1(are:)2.5 E 15(pP)229 426 S
+(rint error messages \(def)254.56 426 Q(ault\))-.1 E 15(qN)229 438 S 2.5(om)
+256.22 438 S(essages, just gi)271.5 438 Q .3 -.15(ve ex)-.25 H(it status).15 E
+12.22(mM)229 450 S(ail back errors)257.89 450 Q 12.78(wW)229 462 S
+(rite back errors \(mail if user not logged in\))258.44 462 Q 15.56(eM)229 474
+S(ail back errors and gi)257.89 474 Q .3 -.15(ve z)-.25 H(ero e).15 E
+(xit stat al)-.15 E -.1(wa)-.1 G(ys).1 E(E)117 494.4 Q F2(\214le/messa)A -.1
+(ge)-.1 G F1 .549(Prepend error messages with the indicated message.)189 494.4
+R .549(If it be)5.549 F .549(gins with a slash,)-.15 F .107(it is assumed to b\
+e the pathname of a \214le containing a message \(this is the rec-)189 506.4 R
+1.317(ommended setting\).)189 518.4 R 1.316
+(Otherwise, it is a literal message.)6.317 F 1.316(The error \214le might)6.316
+F .99
+(contain the name, email address, and/or phone number of a local postmaster)189
+530.4 R .429(who could pro)189 542.4 R .429(vide assistance in to end users.)
+-.15 F .428(If the option is missing or null,)5.429 F .342
+(or if it names a \214le which does not e)189 554.4 R .342
+(xist or which is not readable, no message)-.15 F(is printed.)189 566.4 Q 68.67
+(fS)117 582.6 S -2.25 -.2(av e)194.56 582.6 T 2.399
+(Unix-style \231From\232 lines at the front of headers.)5.1 F 2.399
+(Normally the)7.399 F 4.899(ya)-.15 G(re)496.23 582.6 Q
+(assumed redundant and discarded.)189 594.6 Q(F)117 610.8 Q F2(mode)A F1
+(The \214le mode for queue \214les.)189 610.8 Q(g)117 627 Q F2(n)A F1 .933
+(Set the def)189 627 R .933(ault group id for mailers to run in to)-.1 F F2(n)
+3.433 E F1 5.933(.D)C(ef)408.966 627 Q .933(aults to 1.)-.1 F .934(The v)5.934
+F(alue)-.25 E(can also be gi)189 639 Q -.15(ve)-.25 G 2.5(na).15 G 2.5(sas)
+264.69 639 S(ymbolic group name.)281.91 639 Q 64.78(GA)117 655.2 S(llo)196.22
+655.2 Q 3.492(wf)-.25 G .992(uzzy matching on the GECOS \214eld.)220.572 655.2
+R .991(If this \215ag is set, and the usual)5.991 F .793(user name lookups f)
+189 667.2 R .793(ail \(that is, there is no alias with this name and a)-.1 F F2
+-.1(ge)3.294 G(tpw-).1 E(nam)189 679.2 Q F1 -.1(fa)3.702 G 1.202
+(ils\), sequentially search the passw).1 F 1.201
+(ord \214le for a matching entry in the)-.1 F 1.446(GECOS \214eld.)189 691.2 R
+1.446(This also requires that MA)6.446 F 1.446(TCHGECOS be turned on during)
+-1.11 F 2.5(compilation. This)189 703.2 R(option is not recommended.)2.5 E EP
+%%Page: 35 30
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-35)452.9 60 Q/F1 10/Times-Roman@0 SF(h)117 96 Q/F2 10/Times-Italic@0 SF
+(N)A F1 1.274(The maximum hop count.)189 96 R 1.274(Messages that ha)6.274 F
+1.574 -.15(ve b)-.2 H 1.273(een processed more than).15 F F2(N)3.773 E F1
+(times are assumed to be in a loop and are rejected.)189 108 Q(Def)5 E
+(aults to 25.)-.1 E(H)117 124.2 Q F2(\214le)A F1
+(Specify the help \214le for SMTP)189 124.2 Q(.)-1.11 E 69.22(iI)117 140.4 S
+1.014(gnore dots in incoming messages.)192.33 140.4 R 1.014(This is al)6.014 F
+-.1(wa)-.1 G 1.014(ys disabled \(that is, dots are).1 F(al)189 152.4 Q -.1(wa)
+-.1 G(ys accepted\) when reading SMTP mail.).1 E 68.67(II)117 168.6 S .62
+(nsist that the BIND name serv)192.33 168.6 R .619(er be running to resolv)-.15
+F 3.119(eh)-.15 G .619(ost names.)421.524 168.6 R .619(If this is)5.619 F .945
+(not set and the name serv)189 180.6 R .945(er is not running, the)-.15 F F2
+(/etc/hosts)3.445 E F1 .945(\214le will be consid-)3.445 F .188(ered complete.)
+189 192.6 R .188(In general, you do w)5.188 F .188
+(ant to set this option if your)-.1 F F2(/etc/hosts)2.687 E F1(\214le)2.687 E
+.412(does not include all hosts kno)189 204.6 R .412
+(wn to you or if you are using the MX \(mail for)-.25 F(-)-.2 E -.1(wa)189
+216.6 S .315(rding\) feature of the BIND name serv).1 F(er)-.15 E 5.315(.T)-.55
+G .315(he name serv)373.955 216.6 R .314(er will still be con-)-.15 F 1.522
+(sulted e)189 228.6 R -.15(ve)-.25 G 4.022(ni).15 G 4.022(ft)242.194 228.6 S
+1.523(his option is not set, b)252.326 228.6 R(ut)-.2 E F2(sendmail)4.023 E F1
+1.523(will feel free to resort to)4.023 F(reading)189 240.6 Q F2(/etc/hosts)
+3.053 E F1 .553(if the name serv)3.053 F .552(er is not a)-.15 F -.25(va)-.2 G
+3.052(ilable. Thus,).25 F .552(you should)3.052 F F2(ne)3.052 E(ver)-.15 E F1
+(set this option if you do not run the name serv)189 252.6 Q(er)-.15 E(.)-.55 E
+69.22(jI)117 268.8 S 3.128(fs)192.33 268.8 S .628
+(et, send error messages in MIME format \(see RFC1341 and RFC1344 for)202.678
+268.8 R(details\).)189 280.8 Q(J)117 297 Q F2(path)A F1 4.923
+(Set the path for searching for users' .forw)189 297 R 4.923(ard \214les.)-.1 F
+4.922(The def)9.922 F 4.922(ault is)-.1 F(\231$z/.forw)189 309 Q 2.868
+(ard\232. Some)-.1 F .368
+(sites that use the automounter may prefer to change this)2.868 F .676
+(to \231/v)189 321 R(ar/forw)-.25 E .676
+(ard/$u\232 to search a \214le with the same name as the user in a sys-)-.1 F
+.924(tem directory)189 333 R 5.924(.I)-.65 G 3.424(tc)254.628 333 S .924
+(an also be set to a sequence of paths separated by colons;)265.272 333 R F2
+(sendmail)189 345 Q F1 .645
+(stops at the \214rst \214le it can successfully and safely open.)3.146 F -.15
+(Fo)5.645 G 3.145(re).15 G(xam-)483.45 345 Q 1.535(ple, \231/v)189 357 R
+(ar/forw)-.25 E(ard/$u:$z/.forw)-.1 E 1.535(ard\232 will search \214rst in /v)
+-.1 F(ar/forw)-.25 E(ard/)-.1 E F2(username)A F1(and then in)189 369 Q F2
+(~username)2.5 E F1(/.forw)A(ard \(b)-.1 E
+(ut only if the \214rst \214le does not e)-.2 E(xist\).)-.15 E(k)117 385.2 Q F2
+(N)A F1 .196
+(The maximum number of open connections that will be cached at a time.)189
+385.2 R(The)5.196 E(def)189 397.2 Q 1.956(ault is one.)-.1 F 1.956
+(This delays closing the current connection until either this)6.956 F(in)189
+409.2 Q -.2(vo)-.4 G .516(cation of).2 F F2(sendmail)3.016 E F1 .516
+(needs to connect to another host or it terminates.)3.016 F(Set-)5.515 E 1.958
+(ting it to zero def)189 421.2 R 1.958(aults to the old beha)-.1 F(vior)-.2 E
+4.459(,t)-.4 G 1.959(hat is, connections are closed)379.244 421.2 R
+(immediately)189 433.2 Q(.)-.65 E(K)117 449.4 Q F2(timeout)A F1 .883
+(The maximum amount of time a cached connection will be permitted to idle)189
+449.4 R 2.746(without acti)189 461.4 R(vity)-.25 E 7.746(.I)-.65 G 5.246(ft)
+267.482 461.4 S 2.746(his time is e)278.838 461.4 R 2.746
+(xceeded, the connection is immediately)-.15 F 4.423(closed. This)189 473.4 R
+-.25(va)4.423 G 1.922(lue should be small \(on the order of ten minutes\).).25
+F(Before)6.922 E F2(sendmail)189 485.4 Q F1 1.286
+(uses a cached connection, it al)3.786 F -.1(wa)-.1 G 1.287
+(ys sends a NOOP \(no operation\)).1 F 2.058
+(command to check the connection; if this f)189 497.4 R 2.058
+(ails, it reopens the connection.)-.1 F .478(This k)189 509.4 R .478
+(eeps your end from f)-.1 F .478(ailing if the other end times out.)-.1 F .478
+(The point of this)5.478 F 3.099(option is to be a good netw)189 521.4 R 3.099
+(ork neighbor and a)-.1 F -.2(vo)-.2 G 3.099(id using up e).2 F(xcessi)-.15 E
+-.15(ve)-.25 G(resources on the other end.)189 533.4 Q(The def)5 E
+(ault is \214v)-.1 E 2.5(em)-.15 G(inutes.)383.99 533.4 Q 69.22(lI)117 549.6 S
+3.14(ft)192.33 549.6 S .64(here is an \231Errors-T)201.58 549.6 R .64
+(o:\232 header)-.8 F 3.14(,s)-.4 G .64
+(end error messages to the addresses listed)333.53 549.6 R 3.951(there. The)189
+561.6 R 3.951(yn)-.15 G 1.451(ormally go to the en)247.292 561.6 R -.15(ve)-.4
+G 1.451(lope sender).15 F 6.451(.U)-.55 G 1.451(se of this option causes)
+405.428 561.6 R F2(sendmail)189 573.6 Q F1(to violate RFC 1123.)2.5 E(L)117
+589.8 Q F2(n)A F1(Set the def)189 589.8 Q(ault log le)-.1 E -.15(ve)-.25 G 2.5
+(lt).15 G(o)288.77 589.8 Q F2(n)2.5 E F1 5(.D)C(ef)315.99 589.8 Q(aults to 9.)
+-.1 E 64.22(mS)117 606 S(end to me too, e)194.56 606 Q -.15(ve)-.25 G 2.5(ni)
+.15 G 2.5(fIa)278.04 606 S 2.5(mi)294.14 606 S 2.5(na)307.2 606 S 2.5(na)319.14
+606 S(lias e)331.08 606 Q(xpansion.)-.15 E(M)117 622.2 Q F2 1.666(xv)C(alue)
+-1.666 E F1 1.312(Set the macro)189 622.2 R F2(x)3.812 E F1(to)3.812 E F2
+(value)3.812 E F1 6.312(.T)C 1.312
+(his is intended only for use from the command)306.852 622.2 R(line.)189 634.2
+Q 67(nV)117 650.4 S(alidate the RHS of aliases when reb)195.11 650.4 Q
+(uilding the alias database.)-.2 E 67(oA)117 666.6 S 1.786
+(ssume that the headers may be in old format, i.e., spaces delimit names.)
+196.22 666.6 R .432(This actually turns on an adapti)189 678.6 R .733 -.15
+(ve a)-.25 H .433(lgorithm: if an).15 F 2.933(yr)-.15 G .433
+(ecipient address contains)403.154 678.6 R 5.09(ac)189 690.6 S 2.589
+(omma, parenthesis, or angle brack)202.97 690.6 R 2.589
+(et, it will be assumed that commas)-.1 F .484(already e)189 702.6 R 2.984
+(xist. If)-.15 F .485(this \215ag is not on, only commas delimit names.)2.984 F
+.485(Headers are)5.485 F(al)189 714.6 Q -.1(wa)-.1 G
+(ys output with commas between the names.).1 E EP
+%%Page: 36 31
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-36 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(O)117 96 Q/F2 10
+/Times-Italic@0 SF(options)A F1(Set serv)189 96 Q(er SMTP options.)-.15 E
+(The options are)5 E F2 -.1(ke)2.5 G(y=value)-.2 E F1 2.5(pairs. Kno)2.5 F
+(wn k)-.25 E -.15(ey)-.1 G 2.5(sa).15 G(re:)488.82 96 Q 52.83(Port Name/number)
+229 112.2 R(of listening port \(def)2.5 E(aults to "smtp"\))-.1 E 48.95
+(Addr Address)229 124.2 R(mask \(def)2.5 E(aults IN)-.1 E(ADDR_ANY\))-.35 E
+-.15(Fa)229 136.2 S 41.31(mily Address).15 F -.1(fa)2.5 G(mily \(def).1 E
+(aults to INET\))-.1 E 44.5(Listen Size)229 148.2 R(of listen queue \(def)2.5 E
+(aults to 10\))-.1 E(The)189 164.4 Q F2(Addr)4.114 E F1 1.614
+(ess mask may be a numeric address in dot notation or a netw)B(ork)-.1 E(name.)
+189 176.4 Q(p)117 192.6 Q F2(opt,opt,...)1.666 E F1 1.22(Set the pri)189 192.6
+R -.25(va)-.25 G -.15(cy).25 G F2(opt)3.871 E F1 3.721(ions. `)B(`Pri)-.74 E
+-.25(va)-.25 G -.15(cy).25 G 2.701 -.74('' i).15 H 3.721(sr).74 G 1.221
+(eally a misnomer; man)351.854 192.6 R 3.721(yo)-.15 G 3.721(ft)460.468 192.6 S
+1.221(hese are)470.299 192.6 R 2.419(just a w)189 204.6 R 2.418
+(ay of insisting on stricter adherence to the SMTP protocol.)-.1 F(The)7.418 E
+F2(opt)189 216.6 Q F1(ions can be selected from:)A 40.26(public Allo)229 232.8
+R 2.5(wo)-.25 G(pen access)329.01 232.8 Q 11.38(needmailhelo Insist)229 244.8 R
+(on HELO or EHLO command before MAIL)2.5 E(neede)229 256.8 Q 9.87
+(xpnhelo Insist)-.15 F(on HELO or EHLO command before EXPN)2.5 E(noe)229 268.8
+Q 35.97(xpn Disallo)-.15 F 2.5(wE)-.25 G(XPN entirely)341.23 268.8 Q 12.5
+(needvrfyhelo Insist)229 280.8 R(on HELO or EHLO command before VRFY)2.5 E(no)
+229 292.8 Q 38.75(vrfy Disallo)-.15 F 2.5(wV)-.25 G(RFY entirely)342.34 292.8 Q
+14.71(restrictmailq Restrict)229 304.8 R(mailq command)2.5 E 19.16
+(restrictqrun Restrict)229 316.8 R(\255q command line \215ag)2.5 E 24.16
+(noreceipts Ignore)229 328.8 R(Return-Receipt-T)2.5 E(o: header)-.8 E(goa)229
+340.8 Q -.1(wa)-.15 G 36.91(yD).1 G(isallo)303.98 340.8 Q 2.5(we)-.25 G
+(ssentially all SMTP status queries)339.56 340.8 Q(authw)229 352.8 Q 11.48
+(arnings Put)-.1 F(X-Authentication-W)2.5 E(arning: headers in messages)-.8 E
+1.565(The \231goa)189 369 R -.1(wa)-.15 G 1.565
+(y\232 pseudo-\215ag sets all \215ags e).1 F 1.566
+(xcept \231restrictmailq\232 and \231restric-)-.15 F 4.299(tqrun\232. If)189
+381 R 1.798(mailq is restricted, only people in the same group as the queue)
+4.299 F .946(directory can print the queue.)189 393 R .946
+(If queue runs are restricted, only root and the)5.946 F -.25(ow)189 405 S .178
+(ner of the queue directory can run the queue.).25 F .178(Authentication W)
+5.178 F .178(arnings add)-.8 F -.1(wa)189 417 S .008(rnings about v).1 F .008
+(arious conditions that may indicate attempts to spoof the mail)-.25 F
+(system, such as using an non-standard queue directory)189 429 Q(.)-.65 E(P)117
+445.2 Q F2(postmaster)A F1 1.115
+(If set, copies of error messages will be sent to the named)189 445.2 R F2
+(postmaster)3.614 E F1 6.114(.O)C(nly)491.22 445.2 Q .397(the header of the f)
+189 457.2 R .398(ailed message is sent.)-.1 F .398
+(Since most errors are user problems,)5.398 F .564
+(this is probably not a good idea on lar)189 469.2 R .563(ge sites, and ar)-.18
+F .563(guably contains all sorts)-.18 F .05(of pri)189 481.2 R -.25(va)-.25 G
+.35 -.15(cy v).25 H .05(iolations, b).15 F .05
+(ut it seems to be popular with certain operating systems)-.2 F -.15(ve)189
+493.2 S(ndors.).15 E(q)117 509.4 Q F2(factor)A F1(Use)189 509.4 Q F2(factor)
+3.098 E F1 .597
+(as the multiplier in the map function to decide when to just queue)3.098 F
+.425(up jobs rather than run them.)189 521.4 R .425(This v)5.425 F .425
+(alue is di)-.25 F .426(vided by the dif)-.25 F .426(ference between)-.25 F
+1.064(the current load a)189 533.4 R -.15(ve)-.2 G 1.064(rage and the load a)
+.15 F -.15(ve)-.2 G 1.064(rage limit \().15 F F0(x)A F1 1.063
+(\215ag\) to determine the)3.564 F(maximum message priority that will be sent.)
+189 545.4 Q(Def)5 E(aults to 600000.)-.1 E(Q)117 561.6 Q F2(dir)A F1
+(Use the named)189 561.6 Q F2(dir)2.5 E F1(as the queue directory)2.5 E(.)-.65
+E(r)117 577.8 Q F2(timeouts)1.666 E F1 -.35(Ti)189 577.8 S 3.938
+(meout reads after).35 F F2(time)6.438 E F1(interv)6.438 E 6.438(al. The)-.25 F
+F2(timeouts)6.438 E F1(ar)6.438 E 3.938(gument is a list of)-.18 F F2 -.1(ke)
+189 589.8 S(ywor)-.2 E(d=value)-.37 E F1 3.61(pairs. The)3.61 F 1.11
+(recognized timeouts and their def)3.61 F 1.11(ault v)-.1 F 1.11(alues, and)
+-.25 F(their minimum v)189 601.8 Q
+(alues speci\214ed in RFC 1123 section 5.3.2 are:)-.25 E EP
+%%Page: 37 32
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-37)452.9 60 Q/F1 10/Times-Roman@0 SF 23.6(initial w)229 96 R
+(ait for initial greeting message [5m, 5m])-.1 E 29.72(helo reply)229 108 R
+(to HELO or EHLO command [5m, none])2.5 E 29.16(mail reply)229 120 R
+(to MAIL command [10m, 5m])2.5 E 31.39(rcpt reply)229 132 R
+(to RCPT command [1h, 5m])2.5 E 16.94(datainit reply)229 144 R(to D)2.5 E -1.21
+-1.11(AT A)-.4 H(command [5m, 2m])3.61 E 8.06(datablock data)229 156 R
+(block read [1h, 3m])2.5 E 12.5(data\214nal reply)229 168 R(to \214nal `)2.5 E
+(`.)-.74 E 1.48 -.74('' i)-.7 H 2.5(nd).74 G(ata [1h, 10m])363.47 168 Q 32.5
+(rset reply)229 180 R(to RSET command [5m, none])2.5 E 31.38(quit reply)229 192
+R(to Q)2.5 E(UIT command [2m, none])-.1 E 28.05(misc reply)229 204 R
+(to NOOP and VERB commands [2m, none])2.5 E 7.5(command command)229 216 R
+(read [1h, 5m])2.5 E 26.94(ident IDENT)229 228 R(protocol timeout [30s, none])
+2.5 E .798(All b)189 244.2 R .798(ut \231command\232 apply to client SMTP)-.2 F
+5.798(.F)-1.11 G .798(or back compatibility)373.406 244.2 R 3.299(,at)-.65 G
+(imeout)476.22 244.2 Q(with no `)189 256.2 Q(`k)-.74 E -.15(ey)-.1 G -.1(wo).15
+G(rd=').1 E 2.5('p)-.74 G(art will set all of the longer v)281.4 256.2 Q
+(alues.)-.25 E 65.33(RN)117 272.4 S(ormally)196.22 272.4 Q(,)-.65 E/F2 10
+/Times-Italic@0 SF(sendmail)4.154 E F1 1.653(tries to eliminate an)4.154 F
+4.153(yu)-.15 G 1.653(nnecessary e)371.721 272.4 R 1.653(xplicit routes when)
+-.15 F .931(sending an error message \(as discussed in RFC 1123 \247 5.2.6\).)
+189 284.4 R -.15(Fo)5.931 G 3.431(re).15 G(xample,)472.06 284.4 Q
+(when sending an error message to)189 296.4 Q(<@kno)229 312.6 Q(wn1,@kno)-.25 E
+(wn2,@unkno)-.25 E(wn:user@kno)-.25 E(wn3>)-.25 E F2(sendmail)189 328.8 Q F1
+.46(will strip of)2.96 F 2.96(ft)-.25 G .46(he \231@kno)284.48 328.8 R .46
+(wn1\232 in order to mak)-.25 F 2.96(et)-.1 G .46(he route as direct as)422.74
+328.8 R 3.429(possible. Ho)189 340.8 R(we)-.25 E -.15(ve)-.25 G 1.729 -.4(r, i)
+.15 H 3.429(ft).4 G(he)284.057 340.8 Q F0(R)3.429 E F1 .929
+(option is set, this will be disabled, and the mail)3.429 F .362
+(will be sent to the \214rst address in the route, e)189 352.8 R -.15(ve)-.25 G
+2.862(ni).15 G 2.862(fl)391.452 352.8 S .362(ater addresses are kno)400.424
+352.8 R(wn.)-.25 E(This may be useful if you are caught behind a \214re)189
+364.8 Q -.1(wa)-.25 G(ll.).1 E 68.11(sB)117 381 S 2.729(es)195.67 381 S(uper)
+206.729 381 Q .229(-safe when running things, i.e., al)-.2 F -.1(wa)-.1 G .229
+(ys instantiate the queue \214le, e).1 F -.15(ve)-.25 G(n).15 E .739
+(if you are going to attempt immediate deli)189 393 R -.15(ve)-.25 G(ry).15 E
+(.)-.65 E F2(Sendmail)5.739 E F1(al)3.239 E -.1(wa)-.1 G .739(ys instantiates)
+.1 F(the queue \214le before returning control the client under an)189 405 Q
+2.5(yc)-.15 G(ircumstances.)429.35 405 Q(S)117 421.2 Q F2(\214le)A F1
+(Log statistics in the named)189 421.2 Q F2(\214le)2.5 E F1(.)A(t)117 437.4 Q
+F2(tzinfo)A F1 .716(Set the local time zone info to)189 437.4 R F2(tzinfo)3.217
+E F1 3.217<8a66>3.217 G .717(or e)358.499 437.4 R .717
+(xample, \231PST8PDT\232.)-.15 F(Actually)5.717 E(,)-.65 E .315
+(if this is not set, the TZ en)189 449.4 R .314(vironment v)-.4 F .314
+(ariable is cleared \(so the system def)-.25 F(ault)-.1 E .55
+(is used\); if set b)189 461.4 R .55(ut null, the user')-.2 F 3.051(sT)-.55 G
+3.051(Zv)334.032 461.4 S .551(ariable is used, and if set and non-null)347.943
+461.4 R(the TZ v)189 473.4 Q(ariable is set to this v)-.25 E(alue.)-.25 E(T)117
+489.6 Q F2(rtime/wtime)A F1 1.604(Set the queue timeout to)189 489.6 R F2
+(rtime)4.103 E F1 6.603(.A)C 1.603(fter this interv)334.172 489.6 R 1.603
+(al, messages that ha)-.25 F 1.903 -.15(ve n)-.2 H(ot).15 E 1.251
+(been successfully sent will be returned to the sender)189 501.6 R 6.252(.D)
+-.55 G(ef)422.724 501.6 Q 1.252(aults to \214v)-.1 F 3.752(ed)-.15 G(ays.)
+488.17 501.6 Q .546(The optional)189 513.6 R F2(wtime)3.046 E F1 .546
+(is the time after which a w)3.046 F .546(arning message is sent.)-.1 F .546
+(If it is)5.546 F(missing or zero then no w)189 525.6 Q
+(arning messages are sent.)-.1 E(u)117 541.8 Q F2(n)A F1 .175(Set the def)189
+541.8 R .175(ault userid for mailers to)-.1 F F2(n)2.675 E F1 5.175(.M)C .175
+(ailers without the)355.28 541.8 R F2(S)2.676 E F1 .176(\215ag in the mailer)
+2.676 F .084(de\214nition will run as this user)189 553.8 R 5.084(.D)-.55 G(ef)
+322.844 553.8 Q .084(aults to 1.)-.1 F .084(The v)5.084 F .084
+(alue can also be gi)-.25 F -.15(ve)-.25 G 2.583(na).15 G 2.583(sa)493.087
+553.8 S(symbolic user name.)189 565.8 Q(U)117 582 Q F2(udbspec)A F1
+(The user database speci\214cation.)189 582 Q 67(vR)117 598.2 S .411(un in v)
+195.67 598.2 R .411(erbose mode.)-.15 F .411(If this is set,)5.411 F F2
+(sendmail)2.912 E F1 .412(adjusts options)2.912 F F0(c)2.912 E F1(\(don')2.912
+E 2.912(tc)-.18 G(onnect)477.34 598.2 Q .428(to e)189 610.2 R(xpensi)-.15 E
+.728 -.15(ve m)-.25 H .428(ailers\) and).15 F F0(d)2.928 E F1(\(deli)2.928 E
+-.15(ve)-.25 G .428(ry mode\) so that all mail is deli).15 F -.15(ve)-.25 G
+.427(red com-).15 F .048
+(pletely in a single job so that you can see the entire deli)189 622.2 R -.15
+(ve)-.25 G .048(ry process.).15 F(Option)5.048 E F0(v)2.548 E F1(should)189
+634.2 Q F2(ne)3.39 E(ver)-.15 E F1 .889
+(be set in the con\214guration \214le; it is intended for command line)3.39 F
+(use only)189 646.2 Q(.)-.65 E(V)117 662.4 Q F2(fallbac)A(khost)-.2 E F1 .963
+(If speci\214ed, the)189 662.4 R F2(fallbac)3.464 E(khost)-.2 E F1 .964
+(acts lik)3.464 F 3.464(eav)-.1 G .964(ery lo)358.606 662.4 R 3.464(wp)-.25 G
+.964(riority MX on e)398.054 662.4 R -.15(ve)-.25 G .964(ry host.).15 F
+(This is intended to be used by sites with poor netw)189 674.4 Q(ork connecti)
+-.1 E(vity)-.25 E(.)-.65 E 64.78(wI)117 690.6 S 4.06(fy)192.33 690.6 S 1.56
+(ou are the \231best\232 \(that is, lo)204.72 690.6 R 1.56
+(west preference\) MX for a gi)-.25 F -.15(ve)-.25 G 4.06(nh).15 G 1.56
+(ost, you)470.77 690.6 R .433
+(should normally detect this situation and treat that condition specially)189
+702.6 R 2.933(,b)-.65 G 2.933(yf)481.277 702.6 S(or)492.54 702.6 Q(-)-.2 E -.1
+(wa)189 714.6 S .594
+(rding the mail to a UUCP feed, treating it as local, or whate).1 F -.15(ve)
+-.25 G 4.193 -.55(r. H).15 H -.25(ow).55 G -2.15 -.25(ev e).25 H -.4(r,).25 G
+EP
+%%Page: 38 33
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-38 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 1.897
+(in some cases \(such as Internet \214re)189 96 R -.1(wa)-.25 G 1.898
+(lls\) you may w).1 F 1.898(ant to try to connect)-.1 F .352
+(directly to that host as though it had no MX records at all.)189 108 R .352
+(Setting this option)5.352 F(causes)189 120 Q/F2 10/Times-Italic@0 SF(sendmail)
+3.032 E F1 .532(to try this.)3.032 F .532(The do)5.532 F .533
+(wnside is that errors in your con\214guration)-.25 F .543(are lik)189 132 R
+.543(ely to be diagnosed as \231host unkno)-.1 F .542
+(wn\232 or \231message timed out\232 instead)-.25 F
+(of something more meaningful.)189 144 Q(This option is disrecommended.)5 E(x)
+117 160.2 Q F2(LA)A F1 .108(When the system load a)189 160.2 R -.15(ve)-.2 G
+.108(rage e).15 F(xceeds)-.15 E F2(LA)2.608 E F1 2.608(,j)C .109
+(ust queue messages \(i.e., don')367.546 160.2 R 2.609(tt)-.18 G(ry)495.67
+160.2 Q(to send them\).)189 172.2 Q(Def)5 E(aults to 8.)-.1 E(X)117 188.4 Q F2
+(LA)A F1 1.251(When the system load a)189 188.4 R -.15(ve)-.2 G 1.251(rage e)
+.15 F(xceeds)-.15 E F2(LA)3.751 E F1 3.751(,r)C 1.251
+(efuse incoming SMTP connec-)376.097 188.4 R 2.5(tions. Def)189 200.4 R
+(aults to 12.)-.1 E(y)117 216.6 Q F2(fact)A F1 .621(The indicated)189 216.6 R
+F2(fact)3.121 E F1 .621(or is added to the priority \(thus)B F2(lowering)3.122
+E F1 .622(the priority of the)3.122 F 1.384
+(job\) for each recipient, i.e., this v)189 228.6 R 1.383
+(alue penalizes jobs with lar)-.25 F 1.383(ge numbers of)-.18 F 2.5
+(recipients. Def)189 240.6 R(aults to 30000.)-.1 E 64.78(YI)117 256.8 S 3.346
+(fs)192.33 256.8 S .846(et, deli)202.896 256.8 R -.15(ve)-.25 G 3.346(re).15 G
+.847(ach job that is run from the queue in a separate process.)251.118 256.8 R
+(Use)5.847 E .037(this option if you are short of memory)189 268.8 R 2.536(,s)
+-.65 G .036(ince the def)350.024 268.8 R .036(ault tends to consume con-)-.1 F
+(siderable amounts of memory while the queue is being processed.)189 280.8 Q(z)
+117 297 Q F2(fact)A F1 1.644(The indicated)189 297 R F2(fact)4.144 E F1 1.645
+(or is multiplied by the message class \(determined by the)B .923
+(Precedence: \214eld in the user header and the)189 309 R F0(P)3.423 E F1 .923
+(lines in the con\214guration \214le\))3.423 F .819
+(and subtracted from the priority)189 321 R 5.819(.T)-.65 G .819
+(hus, messages with a higher Priority: will)333.255 321 R(be f)189 333 Q -.2
+(avo)-.1 G 2.5(red. Def).2 F(aults to 1800.)-.1 E(Z)117 349.2 Q F2(fact)A F1
+(The)189 349.2 Q F2(fact)3.346 E F1 .846(or is added to the priority e)B -.15
+(ve)-.25 G .846(ry time a job is processed.).15 F .845(Thus, each)5.845 F .942
+(time a job is processed, its priority will be decreased by the indicated v)189
+361.2 R(alue.)-.25 E .297(In most en)189 373.2 R .296
+(vironments this should be positi)-.4 F -.15(ve)-.25 G 2.796(,s).15 G .296
+(ince hosts that are do)378.614 373.2 R .296(wn are all)-.25 F(too often do)189
+385.2 Q(wn for a long time.)-.25 E(Def)5 E(aults to 90000.)-.1 E 67(7S)117
+401.4 S .278(trip input to se)194.56 401.4 R -.15(ve)-.25 G 2.778(nb).15 G .278
+(its for compatibility with old systems.)275.272 401.4 R .279(This shouldn')
+5.279 F 2.779(tb)-.18 G(e)499.56 401.4 Q(necessary)189 413.4 Q(.)-.65 E .78
+(All options can be speci\214ed on the command line using the \255o \215ag, b)
+117 429.6 R .779(ut most will cause)-.2 F F2(send-)3.279 E(mail)117 441.6 Q F1
+.236(to relinquish its setuid permissions.)2.736 F .237
+(The options that will not cause this are b, d, e, i, L, m,)5.237 F .175
+(o, p, r)117 453.6 R 2.675(,s)-.4 G 2.675(,v)149.345 453.6 S 2.675(,C)158.87
+453.6 S 2.675(,a)170.715 453.6 S .174(nd 7.)180.33 453.6 R .174(Also, M \(de\
+\214ne macro\) when de\214ning the r or s macros is also considered)5.174 F
+(\231safe\232.)117 465.6 Q F0 2.5(5.1.7. P)102 489.6 R 2.5<8a70>2.5 G -.18(re)
+156.17 489.6 S(cedence de\214nitions).18 E F1 -1.11(Va)142 505.8 S .304
+(lues for the \231Precedence:\232 \214eld may be de\214ned using the)1.11 F F0
+(P)2.805 E F1 .305(control line.)2.805 F .305(The syntax of)5.305 F
+(this \214eld is:)117 517.8 Q F0(P)157 534 Q F2(name)A F0(=)A F2(num)A F1 .286
+(When the)117 550.2 R F2(name)2.786 E F1 .285
+(is found in a \231Precedence:\232 \214eld, the message class is set to)2.786 F
+F2(num)2.785 E F1 5.285(.H)C .285(igher num-)459.555 550.2 R .479
+(bers mean higher precedence.)117 562.2 R .479(Numbers less than zero ha)5.479
+F .779 -.15(ve t)-.2 H .48(he special property that if an error).15 F 1.11(occ\
+urs during processing the body of the message will not be returned; this is e)
+117 574.2 R 1.11(xpected to be)-.15 F .678(used for \231b)117 586.2 R .678
+(ulk\232 mail such as through mailing lists.)-.2 F .678(The def)5.678 F .678
+(ault precedence is zero.)-.1 F -.15(Fo)5.678 G 3.178(re).15 G(xam-)483.45
+586.2 Q(ple, our list of precedences is:)117 598.2 Q(P\214rst-class=0)157 614.4
+Q(Pspecial-deli)157 626.4 Q -.15(ve)-.25 G(ry=100).15 E(Plist=\25530)157 638.4
+Q(Pb)157 650.4 Q(ulk=\25560)-.2 E(Pjunk=\255100)157 662.4 Q .8
+(People writing mailing list e)117 678.6 R .799
+(xploders are encouraged to use \231Precedence: list\232.)-.15 F .799(Older v)
+5.799 F(ersions)-.15 E(of)117 690.6 Q F2(sendmail)3.759 E F1 1.259
+(\(which discarded all error returns for ne)3.759 F -.05(ga)-.15 G(ti).05 E
+1.559 -.15(ve p)-.25 H 1.259(recedences\) didn').15 F 3.76(tr)-.18 G 1.26
+(ecognize this)450.25 690.6 R .255(name, gi)117 702.6 R .255(ving it a def)-.25
+F .255(ault precedence of zero.)-.1 F .254(This allo)5.254 F .254
+(ws list maintainers to see error returns on)-.25 F(both old and ne)117 714.6 Q
+2.5(wv)-.25 G(ersions of)193.26 714.6 Q F2(sendmail)2.5 E F1(.)A EP
+%%Page: 39 34
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-39)452.9 60 Q 2.5(5.1.8. V)102 96 R 2.5<8a63>2.5 G(on\214guration v)
+156.16 96 Q(ersion le)-.1 E -.1(ve)-.15 G(l).1 E/F1 10/Times-Roman@0 SF 2.11
+-.8(To p)142 112.2 T(ro).8 E .51
+(vide compatibility with old con\214guration \214les, the)-.15 F F0(V)3.01 E F1
+.51(line has been added to de\214ne)3.01 F .173(some v)117 124.2 R .173
+(ery basic semantics of the con\214guration \214le.)-.15 F .172
+(These are not intended to be long term sup-)5.173 F 1.84(ports; rather)117
+136.2 R 4.34(,t)-.4 G(he)176.66 136.2 Q 4.34(yd)-.15 G 1.84
+(escribe compatibility features which will probably be remo)200.29 136.2 R -.15
+(ve)-.15 G 4.34(di).15 G 4.34(nf)470.78 136.2 S(uture)483.45 136.2 Q(releases.)
+117 148.2 Q F0(N.B.:)142 164.4 Q F1 1.032(these v)3.532 F(ersion)-.15 E/F2 10
+/Times-Italic@0 SF(le)3.532 E(vels)-.15 E F1(ha)3.532 E 1.332 -.15(ve n)-.2 H
+1.032(othing to do with the v).15 F(ersion)-.15 E F2(number)3.532 E F1 1.032
+(on the \214les.)3.532 F -.15(Fo)6.032 G(r).15 E -.15(ex)117 176.4 S .384
+(ample, as of this writing v).15 F .384
+(ersion 8 con\214g \214les \(speci\214cally)-.15 F 2.884(,8)-.65 G .384
+(.6\) used v)373.76 176.4 R .384(ersion le)-.15 F -.15(ve)-.25 G 2.884(l5c).15
+G(on\214gu-)475.11 176.4 Q(rations.)117 188.4 Q .031
+(\231Old\232 con\214guration \214les are de\214ned as v)142 204.6 R .031
+(ersion le)-.15 F -.15(ve)-.25 G 2.531(lo).15 G 2.531(ne. V)359.438 204.6 R
+.031(ersion le)-1.11 F -.15(ve)-.25 G 2.53(lt).15 G .23 -.1(wo \214)433.84
+204.6 T .03(les mak).1 F 2.53(et)-.1 G(he)494.56 204.6 Q(follo)117 216.6 Q
+(wing changes:)-.25 E 12.5(\(1\) Host)122 232.8 R .757(name canoni\214cation \
+\($[ ... $]\) appends a dot if the name is recognized; this gi)3.256 F -.15(ve)
+-.25 G(s).15 E .903(the con\214g \214le a w)148.66 244.8 R .903
+(ay of \214nding out if an)-.1 F .903(ything matched.)-.15 F(\(Actually)5.903 E
+3.403(,t)-.65 G .902(his just initializes)432.186 244.8 R .424
+(the \231host\232 map with the \231\255a.)148.66 256.8 R 5.424<9a8d>-.7 G .424
+(ag \212 you can reset it to an)280.014 256.8 R .424
+(ything you prefer by declar)-.15 F(-)-.2 E(ing the map e)148.66 268.8 Q
+(xplicitly)-.15 E(.\))-.65 E 12.5(\(2\) Def)122 285 R .436(ault host name e)-.1
+F .435(xtension is consistent throughout processing; v)-.15 F .435(ersion le)
+-.15 F -.15(ve)-.25 G 2.935(lo).15 G .435(ne con-)473.855 285 R .828
+(\214gurations turned of)148.66 297 R 3.328(fd)-.25 G .828(omain e)243.384 297
+R .828(xtension \(that is, adding the local domain name\) during)-.15 F .597
+(certain points in processing.)148.66 309 R -1.11(Ve)5.597 G .597(rsion le)1.11
+F -.15(ve)-.25 G 3.097(lt).15 G .797 -.1(wo c)326.822 309 T .597
+(on\214gurations are e).1 F .596(xpected to include a)-.15 F
+(trailing dot to indicate that the name is already canonical.)148.66 321 Q 12.5
+(\(3\) Local)122 337.2 R .176
+(names that are not aliases are passed through a ne)2.675 F 2.676(wd)-.25 G
+.176(istinguished ruleset \214v)388.892 337.2 R .176(e; this)-.15 F .797
+(can be used to append a local relay)148.66 349.2 R 5.797(.T)-.65 G .797
+(his beha)307.676 349.2 R .796(viour can be pre)-.2 F -.15(ve)-.25 G .796
+(nted by resolving the).15 F .62(local name with an initial `@'.)148.66 361.2 R
+.621(That is, something that resolv)5.62 F .621(es to a local mailer and a)-.15
+F .844(user name of \231vikki\232 will be passed through ruleset \214v)148.66
+373.2 R .843(e, b)-.15 F .843(ut a user name of \231@vikki\232)-.2 F .328
+(will ha)148.66 385.2 R .628 -.15(ve t)-.2 H .328
+(he `@' stripped, will not be passed through ruleset \214v).15 F .328(e, b)-.15
+F .328(ut will otherwise be)-.2 F 1.509(treated the same as the prior e)148.66
+397.2 R 4.009(xample. The)-.15 F -.15(ex)4.009 G 1.508
+(pectation is that this might be used to).15 F .907(implement a polic)148.66
+409.2 R 3.407(yw)-.15 G .907(here mail sent to \231vikki\232 w)238.171 409.2 R
+.908(as handled by a central hub, b)-.1 F .908(ut mail)-.2 F
+(sent to \231vikki@localhost\232 w)148.66 421.2 Q(as deli)-.1 E -.15(ve)-.25 G
+(red directly).15 E(.)-.65 E -1.11(Ve)142 437.4 S .229(rsion le)1.11 F -.15(ve)
+-.25 G 2.729(lt).15 G .229(hree \214les allo)199.828 437.4 R 2.729(w#i)-.25 G
+.228(nitiated comments on all lines.)274.374 437.4 R .228
+(Exceptions are backslash)5.228 F(escaped # marks and the $# syntax.)117 449.4
+Q -1.11(Ve)142 465.6 S 1.593(rsion le)1.11 F -.15(ve)-.25 G 4.093(lf).15 G
+1.593(our con\214gurations are completely equi)203.106 465.6 R -.25(va)-.25 G
+1.594(lent to le).25 F -.15(ve)-.25 G 4.094(lt).15 G 1.594(hree for historical)
+429.722 465.6 R(reasons.)117 477.6 Q -1.11(Ve)142 493.8 S .234(rsion le)1.11 F
+-.15(ve)-.25 G 2.734<6c8c>.15 G .534 -.15(ve c)202.618 493.8 T .234
+(on\214guration \214les change the def).15 F .234(ault de\214nition of)-.1 F F0
+($w)2.734 E F1 .234(to be just the \214rst)2.734 F(component of the hostname.)
+117 505.8 Q(The)142 522 Q F0(V)2.64 E F1 .14(line may ha)2.64 F .44 -.15(ve a)
+-.2 H 2.64(no).15 G(ptional)245.8 522 Q F0(/)2.64 E F2(vendor)A F1 .14
+(to indicate that this con\214guration \214le uses modi-)2.64 F
+(\214cations speci\214c to a particular v)117 536 Q(endor)-.15 E/F3 7
+/Times-Roman@0 SF(14)272.1 532 Q F1(.)279.1 536 Q F0 2.5(5.1.9. K)102 560 R 2.5
+<8a6b>2.5 G(ey \214le declaration)157.74 560 Q F1
+(Special maps can be de\214ned using the line:)142 576.2 Q
+(Kmapname mapclass ar)157 592.4 Q(guments)-.18 E(The)117 608.6 Q F2(mapname)
+3.443 E F1 .944(is the handle by which this map is referenced in the re)3.443 F
+.944(writing rules.)-.25 F(The)5.944 E F2(map-)3.444 E(class)117 620.6 Q F1
+.301(is the name of a type of map; these are compiled in to)2.801 F F2
+(sendmail)2.8 E F1 5.3(.T)C(he)410.64 620.6 Q F2(ar)2.8 E(guments)-.37 E F1 .3
+(are inter)2.8 F(-)-.2 E .569(preted depending on the class; typically)117
+632.6 R 3.069(,t)-.65 G .569(here w)286.134 632.6 R .569(ould be a single ar)
+-.1 F .57(gument naming the \214le con-)-.18 F(taining the map.)117 644.6 Q .32
+LW 76 669.2 72 669.2 DL 80 669.2 76 669.2 DL 84 669.2 80 669.2 DL 88 669.2 84
+669.2 DL 92 669.2 88 669.2 DL 96 669.2 92 669.2 DL 100 669.2 96 669.2 DL 104
+669.2 100 669.2 DL 108 669.2 104 669.2 DL 112 669.2 108 669.2 DL 116 669.2 112
+669.2 DL 120 669.2 116 669.2 DL 124 669.2 120 669.2 DL 128 669.2 124 669.2 DL
+132 669.2 128 669.2 DL 136 669.2 132 669.2 DL 140 669.2 136 669.2 DL 144 669.2
+140 669.2 DL 148 669.2 144 669.2 DL 152 669.2 148 669.2 DL 156 669.2 152 669.2
+DL 160 669.2 156 669.2 DL 164 669.2 160 669.2 DL 168 669.2 164 669.2 DL 172
+669.2 168 669.2 DL 176 669.2 172 669.2 DL 180 669.2 176 669.2 DL 184 669.2 180
+669.2 DL 188 669.2 184 669.2 DL 192 669.2 188 669.2 DL 196 669.2 192 669.2 DL
+200 669.2 196 669.2 DL 204 669.2 200 669.2 DL 208 669.2 204 669.2 DL 212 669.2
+208 669.2 DL 216 669.2 212 669.2 DL/F4 5/Times-Roman@0 SF(14)93.6 679.6 Q/F5 8
+/Times-Roman@0 SF .214(And of course, v)3.2 J .214
+(endors are encouraged to add themselv)-.12 F .214
+(es to the list of recognized v)-.12 F .214(endors by editing the routine)-.12
+F/F6 8/Times-Italic@0 SF(setvendor)2.214 E F5(in)2.214 E F6(conf)72 692.4 Q(.c)
+-.12 E F5(.)A EP
+%%Page: 40 35
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-40 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF
+(Maps are referenced using the syntax:)142 96 Q($\()157 112.2 Q/F2 10
+/Times-Italic@0 SF(map k)2.5 E -.3(ey)-.1 G F1($@)2.8 E F2(ar)2.5 E(guments)
+-.37 E F1($:)2.5 E F2(default)2.5 E F1($\))2.5 E .797
+(where either or both of the)117 128.4 R F2(ar)3.297 E(guments)-.37 E F1(or)
+3.297 E F2(default)3.297 E F1 .796(portion may be omitted.)3.297 F(The)5.796 E
+F2(ar)3.296 E(guments)-.37 E F1(may)3.296 E .205(appear more than once.)117
+140.4 R .205(The indicated)5.205 F F2 -.1(ke)2.705 G(y)-.2 E F1(and)2.705 E F2
+(ar)2.705 E(guments)-.37 E F1 .205(are passed to the appropriate mapping)2.705
+F 2.503(function. If)117 152.4 R .003(it returns a v)2.503 F .003
+(alue, it replaces the input.)-.25 F .003(If it does not return a v)5.003 F
+.003(alue and the)-.25 F F2(default)2.503 E F1(is)2.503 E(speci\214ed, the)117
+164.4 Q F2(default)2.5 E F1(replaces the input.)2.5 E
+(Otherwise, the input is unchanged.)5 E .159
+(During replacement of either a map v)142 180.6 R .159(alue or def)-.25 F .159
+(ault the string \231%)-.1 F F2(n)A F1 2.66<9a28>C(where)421.82 180.6 Q F2(n)
+2.66 E F1 .16(is a digit\) is)2.66 F .204(replaced by the corresponding)117
+192.6 R F2(ar)2.704 E(gument)-.37 E F1 5.204(.A)C -.18(rg)294 192.6 S .204
+(ument zero is al).18 F -.1(wa)-.1 G .204(ys the database k).1 F -.15(ey)-.1 G
+5.203(.F)-.5 G .203(or e)468.127 192.6 R(xam-)-.15 E(ple, the rule)117 204.6 Q
+(R$- ! $+)157 220.8 Q($: $\(uucp $1 $@ $2 $: %1 @ %0 . UUCP $\))265 220.8 Q
+.436(Looks up the UUCP name in a \(user de\214ned\) UUCP map; if not found it \
+turns it into \231.UUCP\232)117 237 R 2.5(form. The)117 249 R
+(database might contain records lik)2.5 E(e:)-.1 E(decv)157 265.2 Q 77.43
+(ax %1@%0.DEC.COM)-.25 F 72.19(research %1@%0.A)157 277.2 R(TT)-1.11 E(.COM)
+-.74 E 2.065(The b)142 297.6 R 2.064(uilt in map with both name and class \231\
+host\232 is the host name canonicalization)-.2 F 2.5(lookup. Thus,)117 309.6 R
+(the syntax:)2.5 E($\(host)157 325.8 Q F2(hostname)2.5 E F1($\))A(is equi)117
+342 Q -.25(va)-.25 G(lent to:).25 E($[)157 358.2 Q F2(hostname)A F1($])A 1.783
+(There are four prede\214ned database lookup classes: \231dbm\232, \231btree\
+\232, \231hash\232, and \231nis\232.)142 378.6 R .569
+(The \214rst requires that)117 390.6 R F2(sendmail)3.069 E F1 .569
+(be compiled with the)3.069 F F0(ndbm)3.069 E F1 .568(library; the second tw)
+3.069 F 3.068(or)-.1 G .568(equire the)463.722 390.6 R F0(db)117 402.6 Q F1
+(library)3.198 E 3.198(,a)-.65 G .698(nd the third requires that)167.466 402.6
+R F2(sendmail)3.198 E F1 .698(be compiled with NIS support.)3.198 F .698
+(All four accept)5.698 F .345(as ar)117 414.6 R .344(guments the same optional\
+ \215ags and a \214lename \(or a mapname for NIS; the \214lename is the)-.18 F
+.105(root of the database path, so that \231.db\232 or some other e)117 426.6 R
+.105(xtension appropriate for the database type)-.15 F
+(will be added to get the actual database name\).)117 438.6 Q(Kno)5 E
+(wn \215ags are:)-.25 E 58.86(\255o Indicates)117 454.8 R .21
+(that this map is optional \212 that is, if it cannot be opened, no error is)
+2.71 F(produced, and)189 466.8 Q F2(sendmail)2.5 E F1(will beha)2.5 E .3 -.15
+(ve a)-.2 H 2.5(si).15 G 2.5(ft)348.9 466.8 S(he map e)357.51 466.8 Q(xisted b)
+-.15 E(ut w)-.2 E(as empty)-.1 E(.)-.65 E 56.64(\255N Normally)117 483 R .515
+(when maps are written, the trailing null byte is not included as part)3.015 F
+.8(of the k)189 495 R -.15(ey)-.1 G 5.8(.I)-.5 G 3.3(ft)241.32 495 S .799
+(his \215ag is indicated it will be included.)250.73 495 R .799
+(During lookups, only)5.799 F(the null-byte-included form will be searched.)189
+507 Q(See also)5 E F0(\255O.)2.5 E F1 56.64(\255O If)117 523.2 R(neither)4.388
+E F0<ad4e>4.388 E F1(or)4.388 E F0<ad4f>4.388 E F1 1.888(are speci\214ed,)4.388
+F F2(sendmail)4.388 E F1 1.889(uses an adapti)4.388 F 2.189 -.15(ve a)-.25 H
+1.889(lgorithm to).15 F 1.025
+(decide whether or not to look for null bytes on the end of k)189 535.2 R -.15
+(ey)-.1 G 3.525(s. It).15 F 1.025(starts by)3.525 F .922
+(trying both; if it \214nds an)189 547.2 R 3.422(yk)-.15 G 1.222 -.15(ey w)
+304.29 547.2 T .922(ith a null byte it ne).15 F -.15(ve)-.25 G 3.422(rt).15 G
+.922(ries ag)422.684 547.2 R .922(ain without a)-.05 F .124
+(null byte and vice v)189 559.2 R 2.623(ersa. If)-.15 F .123
+(this \215ag is speci\214ed, it ne)2.623 F -.15(ve)-.25 G 2.623(rt).15 G .123
+(ries with a null byte;)421.288 559.2 R .748(this can speed matches b)189 571.2
+R .748(ut is ne)-.2 F -.15(ve)-.25 G 3.249(rn).15 G(ecessary)341.667 571.2 Q
+5.749(.I)-.65 G 3.249(fb)386.466 571.2 S(oth)398.045 571.2 Q F0<ad4e>3.249 E F1
+(and)3.249 E F0<ad4f>3.249 E F1 .749(are speci-)3.249 F(\214ed,)189 583.2 Q F2
+(sendmail)4.349 E F1 1.849(will ne)4.349 F -.15(ve)-.25 G 4.349(rt).15 G 1.849
+(ry an)300.156 583.2 R 4.349(ym)-.15 G 1.848(atches at all \212 that is, e)
+339.254 583.2 R -.15(ve)-.25 G 1.848(rything will).15 F(appear to f)189 595.2 Q
+(ail.)-.1 E<ad61>117 611.4 Q F2(x)A F1 .106(Append the string)189 611.4 R F2(x)
+2.606 E F1 .107(on successful matches.)2.606 F -.15(Fo)5.107 G 2.607(re).15 G
+.107(xample, the def)387.852 611.4 R(ault)-.1 E F2(host)2.607 E F1(map)2.607 E
+(appends a dot on successful matches.)189 623.4 Q 60.53(\255f Do)117 639.6 R
+(not fold upper to lo)2.5 E(wer case before looking up the k)-.25 E -.15(ey)-.1
+G(.)-.5 E 56.08(\255m Match)117 655.8 R .085(only \(without replacing the v)
+2.585 F 2.585(alue\). If)-.25 F .085(you only care about the e)2.585 F
+(xistence)-.15 E 2.618(of a k)189 667.8 R 2.918 -.15(ey a)-.1 H 2.618
+(nd not the v).15 F 2.619(alue \(as you might when searching the NIS map)-.25 F
+.447(\231hosts.byname\232 for e)189 679.8 R .447(xample\), this \215ag pre)-.15
+F -.15(ve)-.25 G .447(nts the map from substituting the).15 F -.25(va)189 691.8
+S 4.935(lue. Ho).25 F(we)-.25 E -.15(ve)-.25 G 3.235 -.4(r, T).15 H 2.436
+(he \255a ar).4 F 2.436(gument is still appended on a match, and the)-.18 F
+(def)189 703.8 Q(ault is still tak)-.1 E(en if the match f)-.1 E(ails.)-.1 E EP
+%%Page: 41 36
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-41)452.9 60 Q/F1 10/Times-Roman@0 SF(The)142 96 Q/F2 10/Times-Italic@0
+SF(dbm)3.874 E F1 1.374
+(map appends the strings \231.pag\232 and \231.dir\232 to the gi)3.874 F -.15
+(ve)-.25 G 3.874<6e8c>.15 G 1.374(lename; the tw)420.268 96 R(o)-.1 E F2(db)
+3.874 E F1(-)A(based maps append \231.db\232.)117 108 Q -.15(Fo)5 G 2.5(re).15
+G(xample, the map speci\214cation)246.67 108 Q -.15(Ku)157 124.2 S
+(ucp dbm \255o \255N /usr/lib/uucpmap).15 E .77
+(speci\214es an optional map named \231uucp\232 of class \231dbm\232; it al)117
+140.4 R -.1(wa)-.1 G .77(ys has null bytes at the end of).1 F -2.15 -.25(ev e)
+117 152.4 T(ry string, and the data is located in /usr/lib/uucpmap.{dir).25 E
+(,pag}.)-.4 E .023(The program)142 168.6 R F2(mak)2.523 E(emap)-.1 E F1 .023
+(\(8\) can be used to b)B .023(uild an)-.2 F 2.523(yo)-.15 G 2.523(ft)353.097
+168.6 S .023(he three database-oriented maps.)361.73 168.6 R(It)5.022 E(tak)117
+180.6 Q(es the follo)-.1 E(wing \215ags:)-.25 E 60.53(\255f F)117 196.8 R
+(old upper to lo)-.15 E(wer case in the map.)-.25 E 56.64(\255N Include)117 213
+R(null bytes in k)2.5 E -.15(ey)-.1 G(s.).15 E 58.86(\255o Append)117 229.2 R
+(to an e)2.5 E(xisting \(old\) \214le.)-.15 E 60.53(\255r Allo)117 245.4 R
+3.479(wr)-.25 G .979(eplacement of e)220.559 245.4 R .979(xisting k)-.15 F -.15
+(ey)-.1 G .979(s; normally).15 F 3.479(,r)-.65 G .979(e-inserting an e)385.494
+245.4 R .979(xisting k)-.15 F 1.279 -.15(ey i)-.1 H(s).15 E(an error)189 257.4
+Q(.)-.55 E 58.86(\255v Print)117 273.6 R(what is happening.)2.5 E(The)117 289.8
+Q F2(sendmail)2.773 E F1 .273(daemon does not ha)2.773 F .572 -.15(ve t)-.2 H
+2.772(ob).15 G 2.772(er)282.148 289.8 S .272(estarted to read the ne)292.69
+289.8 R 2.772(wm)-.25 G .272(aps as long as you change)399.05 289.8 R .042
+(them in place; \214le locking is used so that the maps w)117 303.8 R(on')-.1 E
+2.542(tb)-.18 G 2.542(er)352.214 303.8 S .042(ead while the)362.526 303.8 R
+2.543(ya)-.15 G .043(re being updated.)427.764 303.8 R/F3 7/Times-Roman@0 SF
+(15)497 299.8 Q F1(There are also tw)142 320 Q 2.5(ob)-.1 G
+(uiltin maps that are, strictly speaking, not database lookups.)223.34 320 Q
+1.563(The \231host\232 map does host domain canoni\214cation; gi)142 336.2 R
+-.15(ve)-.25 G 4.063(nah).15 G 1.563(ost name it calls the name)392.585 336.2 R
+(serv)117 348.2 Q(er to \214nd the canonical name for that host.)-.15 E .106
+(The \231dequote\232 map strips double quotes \("\) from a name.)142 364.4 R
+.106(It does not strip backslashes.)5.106 F(It)5.106 E 1.838
+(will not strip quotes if the resulting string w)117 376.4 R 1.838
+(ould contain unscannable syntax \(that is, basic)-.1 F .601(errors lik)117
+388.4 R 3.101(eu)-.1 G .601(nbalanced angle brack)166.422 388.4 R .601
+(ets; more sophisticated errors such as unkno)-.1 F .6(wn hosts are not)-.25 F
+(check)117 400.4 Q 3.398(ed\). The)-.1 F .899
+(intent is for use when trying to accept mail from systems such as DECnet that)
+3.398 F(routinely quote odd syntax such as)117 412.4 Q("49ers::ubell")157 428.6
+Q 2.5(At)117 444.8 S(ypical usage is probably something lik)129.5 444.8 Q(e:)
+-.1 E(Kdequote dequote)157 461 Q(...)157 485 Q 88.19(R$\255 $:)157 509 R
+($\(dequote $1 $\))2.5 E(R$\255 $+)157 521 Q($: $>3 $1 $2)265 521 Q
+(Care must be tak)117 537.2 Q(en to pre)-.1 E -.15(ve)-.25 G(nt une).15 E
+(xpected results; for e)-.15 E(xample,)-.15 E("|someprogram < input > output")
+157 553.4 Q .084(will ha)117 569.6 R .384 -.15(ve q)-.2 H .083
+(uotes stripped, b).15 F .083
+(ut the result is probably not what you had in mind.)-.2 F -.15(Fo)5.083 G .083
+(rtunately these).15 F(cases are rare.)117 581.6 Q(Ne)142 597.8 Q 2.5(wc)-.25 G
+(lasses can be added in the routine)167.57 597.8 Q F0(setupmaps)2.5 E F1
+(in \214le)2.5 E F0(conf)2.5 E(.c)-.15 E F1(.)A F0 2.5(5.2. Building)87 621.8 R
+2.5(aC)2.5 G(on\214guration File Fr)160.91 621.8 Q(om Scratch)-.18 E F1 1.517
+(Building a con\214guration table from scratch is an e)127 638 R 1.518
+(xtremely dif)-.15 F 1.518(\214cult job)-.25 F 6.518(.F)-.4 G(ortunately)
+441.334 638 Q 4.018(,i)-.65 G 4.018(ti)490.532 638 S(s)500.11 638 Q 1.855
+(almost ne)102 650 R -.15(ve)-.25 G 4.355(rn).15 G 1.855
+(ecessary to do so; nearly e)164.19 650 R -.15(ve)-.25 G 1.855
+(ry situation that may come up may be resolv).15 F 1.855(ed by)-.15 F 1.38
+(changing an e)102 662 R 1.38(xisting table.)-.15 F 1.38(In an)6.38 F 3.88(yc)
+-.15 G 1.381(ase, it is critical that you understand what it is that you are)
+254.4 662 R .32 LW 76 671.6 72 671.6 DL 80 671.6 76 671.6 DL 84 671.6 80 671.6
+DL 88 671.6 84 671.6 DL 92 671.6 88 671.6 DL 96 671.6 92 671.6 DL 100 671.6 96
+671.6 DL 104 671.6 100 671.6 DL 108 671.6 104 671.6 DL 112 671.6 108 671.6 DL
+116 671.6 112 671.6 DL 120 671.6 116 671.6 DL 124 671.6 120 671.6 DL 128 671.6
+124 671.6 DL 132 671.6 128 671.6 DL 136 671.6 132 671.6 DL 140 671.6 136 671.6
+DL 144 671.6 140 671.6 DL 148 671.6 144 671.6 DL 152 671.6 148 671.6 DL 156
+671.6 152 671.6 DL 160 671.6 156 671.6 DL 164 671.6 160 671.6 DL 168 671.6 164
+671.6 DL 172 671.6 168 671.6 DL 176 671.6 172 671.6 DL 180 671.6 176 671.6 DL
+184 671.6 180 671.6 DL 188 671.6 184 671.6 DL 192 671.6 188 671.6 DL 196 671.6
+192 671.6 DL 200 671.6 196 671.6 DL 204 671.6 200 671.6 DL 208 671.6 204 671.6
+DL 212 671.6 208 671.6 DL 216 671.6 212 671.6 DL/F4 5/Times-Roman@0 SF(15)93.6
+682 Q/F5 8/Times-Roman@0 SF .129(That is, don')3.2 J 2.129(tc)-.144 G .129
+(reate ne)147.283 685.2 R 2.129(wm)-.2 G .129(aps and then use)186.437 685.2 R
+/F6 8/Times-Italic@0 SF(mv)2.129 E F5 .129(\(1\) to mo)B .369 -.12(ve t)-.12 H
+.129(hem into place.).12 F 2.129(Ic)4.129 G .128(onsider this a shortf)354.472
+685.2 R .128(all \(a.k.a. b)-.08 F .128(ug\) in)-.16 F F6(sendmail)2.128 E F5
+(which should be \214x)72 694.8 Q(ed in a future release.)-.12 E EP
+%%Page: 42 37
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-42 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF .498
+(trying to do and come up with a philosoph)102 96 R 2.998(yf)-.05 G .498
+(or the con\214guration table.)286.702 96 R .497(This section is intended to)
+5.497 F -.15(ex)102 108 S .67
+(plain what the real purpose of a con\214guration table is and to gi).15 F .97
+-.15(ve y)-.25 H .67(ou some ideas for what your).15 F(philosoph)102 120 Q 2.5
+(ym)-.05 G(ight be.)156.68 120 Q F0 1.32(Do not e)127 136.2 R -.1(ve)-.15 G
+3.82(nc).1 G(onsider)188.2 136.2 Q F1 1.32(writing your o)3.82 F 1.32
+(wn con\214guration \214le without carefully studying RFC)-.25 F
+(821, 822, and 1123.)102 148.2 Q -1.1(Yo)5 G 2.5(us)1.1 G
+(hould also read RFC 976 if you are doing UUCP e)208.95 148.2 Q(xchange.)-.15 E
+F0 2.5(5.2.1. What)102 172.2 R -.25(yo)2.5 G 2.5(ua).25 G .36 -.18(re t)178.7
+172.2 T(rying to do).18 E F1 .82
+(The con\214guration table has three major purposes.)142 188.4 R .821
+(The \214rst and simplest is to set up the)5.821 F(en)117 200.4 Q .35
+(vironment for)-.4 F/F2 10/Times-Italic@0 SF(sendmail)2.85 E F1 5.35(.T)C .35
+(his in)234.58 200.4 R -.2(vo)-.4 G(lv).2 E .35
+(es setting the options, de\214ning a fe)-.15 F 2.85(wc)-.25 G .35
+(ritical macros, etc.)429.43 200.4 R(Since these are described in other places\
+, we will not go into more detail here.)117 212.4 Q .283
+(The second purpose is to re)142 228.6 R .284(write addresses in the message.)
+-.25 F .284(This should typically be done)5.284 F .214(in tw)117 240.6 R 2.714
+(op)-.1 G 2.713(hases. The)150.108 240.6 R .213
+(\214rst phase maps addresses in an)2.713 F 2.713(yf)-.15 G .213
+(ormat into a canonical form.)337.182 240.6 R .213(This should)5.213 F .156
+(be done in ruleset three.)117 252.6 R .157
+(The second phase maps this canonical form into the syntax appropriate)5.156 F
+1.998(for the recei)117 264.6 R 1.997(ving mailer)-.25 F(.)-.55 E F2(Sendmail)
+6.997 E F1 1.997(does this in three subphases.)4.497 F 1.997
+(Rulesets one and tw)6.997 F 4.497(oa)-.1 G(re)496.23 264.6 Q .043
+(applied to all sender and recipient addresses respecti)117 276.6 R -.15(ve)
+-.25 G(ly).15 E 5.043(.A)-.65 G .043(fter this, you may specify per)357.904
+276.6 R(-mailer)-.2 E 2.723
+(rulesets for both sender and recipient addresses; this allo)117 288.6 R 2.723
+(ws mailer)-.25 F 2.723(-speci\214c customization.)-.2 F(Finally)117 300.6 Q
+2.5(,r)-.65 G(uleset four is applied to do an)153.02 300.6 Q 2.5(yd)-.15 G(ef)
+283.69 300.6 Q(ault con)-.1 E -.15(ve)-.4 G(rsion to e).15 E(xternal form.)-.15
+E .785(The third purpose is to map addresses into the actual set of instructio\
+ns necessary to get)142 316.8 R .154(the message deli)117 328.8 R -.15(ve)-.25
+G 2.654(red. Ruleset).15 F .154(zero must resolv)2.654 F 2.654(et)-.15 G 2.654
+(ot)321.658 328.8 S .153(he internal form, which is in turn used as a)332.092
+328.8 R .446(pointer to a mailer descriptor)117 340.8 R 5.446(.T)-.55 G .446
+(he mailer descriptor describes the interf)248.38 340.8 R .447
+(ace requirements of the)-.1 F(mailer)117 352.8 Q(.)-.55 E F0 2.5
+(5.2.2. Philosoph)102 376.8 R(y)-.15 E F1 1.481(The particular philosoph)142
+393 R 3.981(yy)-.05 G 1.481(ou choose will depend hea)257.213 393 R 1.481
+(vily on the size and structure of)-.2 F .55(your or)117 405 R -.05(ga)-.18 G
+3.05(nization. I).05 F .55(will present a fe)3.05 F 3.05(wp)-.25 G .55
+(ossible philosophies here.)283.39 405 R .55(There are as man)5.55 F 3.05(yp)
+-.15 G(hiloso-)476.22 405 Q
+(phies as there are con\214g designers; feel free to de)117 417 Q -.15(ve)-.25
+G(lop your o).15 E(wn.)-.25 E .388
+(One general point applies to all of these philosophies: it is almost al)142
+433.2 R -.1(wa)-.1 G .388(ys a mistak).1 F 2.888(et)-.1 G 2.888(ot)485.002
+433.2 S(ry)495.67 433.2 Q .176(to do full host route resolution.)117 445.2 R
+-.15(Fo)5.176 G 2.676(re).15 G .176
+(xample, if you are on a UUCP-only site and you are trying)267.652 445.2 R
+1.223(to get names of the form \231user@host\232 to the Internet, it does not \
+pay to route them to \231xyz-)117 457.2 R -.25(va)117 469.2 S(x!decv).25 E
+(ax!ucb)-.25 E -.25(va)-.15 G .304
+(x!c70!user@host\232 since you then depend on se).25 F -.15(ve)-.25 G .305
+(ral links not under your con-).15 F .996(trol, some of which are lik)117 481.2
+R .996(ely to misparse it an)-.1 F(yw)-.15 E(ay)-.1 E 5.996(.T)-.65 G .996
+(he best approach to this problem is to)347.32 481.2 R 1.048(simply forw)117
+493.2 R 1.048(ard the message for \231user@host\232 to \231xyzv)-.1 F 1.049
+(ax\232 and let xyzv)-.25 F 1.049(ax w)-.25 F 1.049(orry about it from)-.1 F
+3.606(there. In)117 505.2 R(summary)3.606 E 3.606(,j)-.65 G 1.106
+(ust get the message closer to the destination, rather than determining the)
+202.988 505.2 R(full path.)117 517.2 Q F0 2.5(5.2.2.1. Lar)117 541.2 R
+(ge site, many hosts \212 minimum inf)-.1 E(ormation)-.25 E F1(Berk)157 557.4 Q
+(ele)-.1 E 3.018(yi)-.15 G 3.018(sa)198.648 557.4 S 3.018(ne)209.996 557.4 S
+.518(xample of a lar)222.304 557.4 R .518(ge site, i.e., more than tw)-.18 F
+3.018(oo)-.1 G 3.018(rt)400.266 557.4 S .519(hree hosts and multiple)409.394
+557.4 R .444(mail connections.)132 569.4 R 2.044 -.8(We h)5.444 H -2.25 -.2
+(av e).8 H .443(decided that the only reasonable philosoph)3.144 F 2.943(yi)
+-.05 G 2.943(no)429.634 569.4 S .443(ur en)442.577 569.4 R(vironment)-.4 E .312
+(is to designate one host as the guru for our site.)132 581.4 R .312
+(It must be able to resolv)5.312 F 2.812(ea)-.15 G .612 -.15(ny p)438.504 581.4
+T .312(iece of mail).15 F 1.083(it recei)132 593.4 R -.15(ve)-.25 G 3.583
+(s. The).15 F 1.083(other sites should ha)3.583 F 1.383 -.15(ve t)-.2 H 1.083
+(he minimum amount of information the).15 F 3.582(yc)-.15 G 1.082(an get)
+478.758 593.4 R -2.3 -.15(aw a)132 605.4 T 2.635(yw).15 G 2.635(ith. In)162.705
+605.4 R .135(addition, an)2.635 F 2.635(yi)-.15 G .135(nformation the)249.485
+605.4 R 2.635(yd)-.15 G 2.635(oh)321.265 605.4 S -2.25 -.2(av e)333.9 605.4 T
+.136(should be hints rather than solid infor)2.835 F(-)-.2 E(mation.)132 617.4
+Q -.15(Fo)157 633.6 S 6.71(re).15 G 4.209
+(xample, a typical site on our local ether netw)181.74 633.6 R 4.209
+(ork is \231monet\232 \(actually)-.1 F(\231monet.CS.Berk)132 645.6 Q(ele)-.1 E
+-.65(y.)-.15 G 3.887(EDU\232\). When).65 F 1.387(monet recei)3.887 F -.15(ve)
+-.25 G 3.887(sm).15 G 1.387(ail for deli)354.258 645.6 R -.15(ve)-.25 G(ry).15
+E 3.887(,i)-.65 G 3.887(tc)424.579 645.6 S 1.387(hecks whether it)435.686 645.6
+R(kno)132 657.6 Q 1.342(ws that the destination host is directly reachable; if\
+ so, mail is sent to that host.)-.25 F 1.342(If it)6.342 F(recei)132 669.6 Q
+-.15(ve)-.25 G 2.915(sm).15 G .415(ail for an)175.055 669.6 R 2.915(yu)-.15 G
+(nkno)224.75 669.6 Q .415(wn host, it just passes it directly to \231ucb)-.25 F
+-.25(va)-.15 G(x.CS.Berk).25 E(ele)-.1 E -.65(y.)-.15 G(EDU\232,).65 E .178
+(our master host.)132 681.6 R(Ucb)5.178 E -.25(va)-.15 G 2.678(xm).25 G .177
+(ay determine that the host name is ille)242.852 681.6 R -.05(ga)-.15 G 2.677
+(la).05 G .177(nd reject the message,)415.159 681.6 R .754
+(or may be able to do deli)132 693.6 R -.15(ve)-.25 G(ry).15 E 5.754(.H)-.65 G
+-.25(ow)268.146 693.6 S -2.15 -.25(ev e).25 H 1.554 -.4(r, i).25 H 3.254(ti).4
+G 3.254(si)313.874 693.6 S .754(mportant to note that when a ne)323.798 693.6 R
+3.254(wm)-.25 G .754(ail con-)472.976 693.6 R .164
+(nection is added, the only host that)132 705.6 R F2(must)2.664 E F1(ha)2.664 E
+.464 -.15(ve i)-.2 H .164(ts tables updated is ucb).15 F -.25(va)-.15 G .164
+(x; the others).25 F F2(may)2.664 E F1(be)2.664 E(updated if con)132 717.6 Q
+-.15(ve)-.4 G(nient, b).15 E(ut this is not critical.)-.2 E EP
+%%Page: 43 38
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-43)452.9 60 Q/F1 10/Times-Roman@0 SF 2.121
+(This picture is slightly muddied due to netw)157 96 R 2.122
+(ork connections that are not actually)-.1 F 2.362(located on ucb)132 108 R
+-.25(va)-.15 G 4.862(x. F).25 F 2.362(or e)-.15 F 2.362
+(xample, some UUCP connections are currently on \231ucbarpa.)-.15 F<9a>-.7 E
+(Ho)132 120 Q(we)-.25 E -.15(ve)-.25 G 1.044 -.4(r, m).15 H(onet).4 E/F2 10
+/Times-Italic@0 SF .244(does not)2.744 F F1(kno)2.744 E 2.744(wa)-.25 G .245
+(bout this; the information is hidden totally between ucb)266.34 120 R -.25(va)
+-.15 G(x).25 E 1.045(and ucbarpa.)132 132 R 1.045
+(Mail going from monet to a UUCP host is transferred via the ethernet from)
+6.045 F 1.43(monet to ucb)132 144 R -.25(va)-.15 G 1.43
+(x, then via the ethernet from ucb).25 F -.25(va)-.15 G 3.931(xt).25 G 3.931
+(ou)355.704 144 S 1.431(cbarpa, and then is submitted to)369.635 144 R(UUCP)132
+156 Q 5(.A)-1.11 G(lthough this in)172.28 156 Q -.2(vo)-.4 G(lv).2 E(es some e)
+-.15 E(xtra hops, we feel this is an acceptable tradeof)-.15 E(f.)-.25 E .826
+(An interesting point is that it w)157 172.2 R .826
+(ould be possible to update monet to send appropriate)-.1 F .127
+(UUCP mail directly to ucbarpa if the load got too high; if monet f)132 184.2 R
+.127(ailed to note a host as con-)-.1 F .353(nected to ucbarpa it w)132 196.2 R
+.353(ould go via ucb)-.1 F -.25(va)-.15 G 2.853(xa).25 G 2.852(sb)305.954 196.2
+S .352(efore, and if monet incorrectly sent a message)317.696 196.2 R .395
+(to ucbarpa it w)132 208.2 R .396(ould still be sent by ucbarpa to ucb)-.1 F
+-.25(va)-.15 G 2.896(xa).25 G 2.896(sb)356.654 208.2 S 2.896(efore. The)368.44
+208.2 R .396(only problem that can)2.896 F .901(occur is loops, for e)132 220.2
+R .901(xample, if ucbarpa thought that ucb)-.15 F -.25(va)-.15 G 3.401(xh).25 G
+.9(ad the UUCP connection and)383.75 220.2 R(vice v)132 232.2 Q 2.5(ersa. F)
+-.15 F(or this reason, updates should)-.15 E F2(always)2.5 E F1
+(happen to the master host \214rst.)2.5 E .144(This philosoph)157 248.4 R 2.644
+(yr)-.05 G .145(esults as much from the need to ha)227.798 248.4 R .445 -.15
+(ve a s)-.2 H .145(ingle source for the con\214gu-).15 F .289
+(ration \214les \(typically b)132 260.4 R .289(uilt using)-.2 F F2(m4)2.789 E
+F1 .289(\(1\) or some similar tool\) as an)1.666 F 2.789(yl)-.15 G .288
+(ogical need.)410.664 260.4 R(Maintain-)5.288 E
+(ing more than three separate tables by hand is essentially an impossible job)
+132 272.4 Q(.)-.4 E F0 2.5(5.2.2.2. Small)117 296.4 R(site \212 complete inf)
+2.5 E(ormation)-.25 E F1 3.356(As)157 312.6 S .856(mall site \(tw)171.466 312.6
+R 3.356(oo)-.1 G 3.356(rt)236.434 312.6 S .856(hree hosts and fe)245.9 312.6 R
+3.356(we)-.25 G .856(xternal connections\) may \214nd it more rea-)330.564
+312.6 R .435(sonable to ha)132 324.6 R .735 -.15(ve c)-.2 H .435
+(omplete information at each host.).15 F .435(This w)5.435 F .435
+(ould require that each host kno)-.1 F(w)-.25 E -.15(ex)132 336.6 S .185
+(actly where each netw).15 F .185
+(ork connection is, possibly including the names of each host on that)-.1 F
+(netw)132 348.6 Q 3.465(ork. As)-.1 F .965
+(long as the site remains small and the con\214guration remains relati)3.465 F
+-.15(ve)-.25 G .964(ly static,).15 F
+(the update problem will probably not be too great.)132 360.6 Q F0 2.5
+(5.2.2.3. Single)117 384.6 R(host)2.5 E F1 .117(This is in some sense the tri)
+157 400.8 R .117(vial case.)-.25 F .117
+(The only major issue is trying to insure that you)5.117 F(don')132 412.8 Q
+3.425(th)-.18 G -2.25 -.2(av e)161.355 412.8 T .925(to kno)3.625 F 3.425(wt)
+-.25 G .925(oo much about your en)217.69 412.8 R 3.425(vironment. F)-.4 F .925
+(or e)-.15 F .924(xample, if you ha)-.15 F 1.224 -.15(ve a U)-.2 H(UCP).15 E
+.614(connection you might \214nd it useful to kno)132 424.8 R 3.115(wa)-.25 G
+.615(bout the names of hosts connected directly to)318.885 424.8 R(you, b)132
+436.8 Q
+(ut this is really not necessary since this may be determined from the syntax.)
+-.2 E F0 2.5(5.2.2.4. A)117 460.8 R(completely differ)2.5 E(ent philosoph)-.18
+E(y)-.15 E F1(This is adapted from Bruce Lilly)157 477 Q 5(.A)-.65 G .3 -.15
+(ny e)301.89 477 T(rrors in interpretation are mine.).15 E .065
+(Do minimal changes in ruleset 3: \214x some common b)157 493.2 R .064
+(ut unambiguous errors \(e.g. trail-)-.2 F 2.758
+(ing dot on domains\) and hide bang paths foo!bar into bar@foo.UUCP)132 505.2 R
+7.759(.T)-1.11 G 2.759(he resulting)454.301 505.2 R("canonical" form is an)132
+517.2 Q 2.5(yv)-.15 G(alid RFC822/RFC1123/RFC976 address.)233.63 517.2 Q 1.388
+(Ruleset 0 does the b)157 533.4 R 1.387(ulk of the w)-.2 F 3.887(ork. It)-.1 F
+(remo)3.887 E -.15(ve)-.15 G 3.887(st).15 G 1.387
+(he trailing "@.UUCP" that hides)367.472 533.4 R .66(bang paths, strips an)132
+545.4 R .661(ything not needed to resolv)-.15 F .661
+(e, e.g. the phrase from phrase <route-addr>)-.15 F .497
+(and from named groups, rejects unparseable addresses using $#error)132 557.4 R
+2.996(,a)-.4 G .496(nd \214nally resolv)419.052 557.4 R .496(es to)-.15 F 4.324
+(am)132 569.4 S 1.824(ailer/host/user triple.)148.544 569.4 R 1.824
+(Ruleset 0 is rather length)6.824 F 4.325(ya)-.05 G 4.325(si)360.965 569.4 S
+4.325(th)371.96 569.4 S 1.825(as to handle 3 basic address)384.065 569.4 R
+5.373(forms: RFC976 bang paths, RFC1123 %-hacks \(including v)132 581.4 R 5.373
+(anilla RFC822 local-)-.25 F .136(part@domain\), and RFC822 source routes.)132
+593.4 R(It')5.137 E 2.637(sa)-.55 G .137(lso complicated by ha)329.508 593.4 R
+.137(ving to handle named)-.2 F(lists.)132 605.4 Q .617(The header re)157 621.6
+R .616(writing rulesets 1 and 2 remo)-.25 F .916 -.15(ve t)-.15 H .616
+(he trailing "@.UUCP" that hides bang).15 F 2.5(paths. Ruleset)132 633.6 R 2.5
+(2a)2.5 G(lso strips the $# mailer $@ host \(for test mode\).)205.05 633.6 Q
+(Ruleset 4 does absolutely nothing.)157 649.8 Q 1.316(The per)157 666 R 1.316
+(-mailer re)-.2 F 1.316(writing rulesets conform the en)-.25 F -.15(ve)-.4 G
+1.317(lope and header addresses to the).15 F
+(requirements of the speci\214c mailer)132 678 Q(.)-.55 E
+(Lots of rulesets-as-subroutines are used.)157 694.2 Q .35(As a result, header\
+ addresses are subject to minimal munging \(per RFC1123\), and the)157 710.4 R
+(general plan is per RFC822 sect. 3.4.10.)132 722.4 Q EP
+%%Page: 44 39
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-44 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(5.2.3. Rele)102 96 R -.1(va)-.15 G
+(nt issues).1 E/F1 10/Times-Roman@0 SF .584(The canonical form you use should \
+almost certainly be as speci\214ed in the Internet proto-)142 112.2 R 2.604
+(cols RFC819 and RFC822.)117 124.2 R 2.604(Copies of these RFC')7.604 F 5.104
+(sa)-.55 G 2.603(re included on the)347.852 124.2 R/F2 10/Times-Italic@0 SF
+(sendmail)5.103 E F1 2.603(tape as)5.103 F F2(doc/rfc819.lpr)117 136.2 Q F1
+(and)2.5 E F2(doc/rfc822.lpr)2.5 E F1(.)A 2.04
+(RFC822 describes the format of the mail message itself.)142 152.4 R F2
+(Sendmail)7.04 E F1(follo)4.54 E 2.04(ws this RFC)-.25 F(closely)117 164.4 Q
+2.984(,t)-.65 G 2.984(ot)152.944 164.4 S .483(he e)163.708 164.4 R .483
+(xtent that man)-.15 F 2.983(yo)-.15 G 2.983(ft)251.44 164.4 S .483
+(he standards described in this document can not be changed)260.533 164.4 R
+(without changing the code.)117 176.4 Q(In particular)5 E 2.5(,t)-.4 G
+(he follo)286.85 176.4 Q(wing characters ha)-.25 E .3 -.15(ve s)-.2 H
+(pecial interpretations:).15 E 2.5(<>\(\)"\\)157 192.6 S(An)117 208.8 Q 3.036
+(ya)-.15 G .537(ttempt to use these characters for other than their RFC822 pur\
+pose in addresses is proba-)141.546 208.8 R(bly doomed to disaster)117 220.8 Q
+(.)-.55 E 1.327
+(RFC819 describes the speci\214cs of the domain-based addressing.)142 237 R
+1.326(This is touched on in)6.327 F 1.439(RFC822 as well.)117 249 R 1.439
+(Essentially each host is gi)6.439 F -.15(ve)-.25 G 3.939(nan).15 G 1.44
+(ame which is a right-to-left dot quali\214ed)333.711 249 R .232
+(pseudo-path from a distinguished root.)117 261 R .232
+(The elements of the path need not be ph)5.232 F .232(ysical hosts; the)-.05 F
+2.365(domain is logical rather than ph)117 273 R 4.866(ysical. F)-.05 F 2.366
+(or e)-.15 F 2.366(xample, at Berk)-.15 F(ele)-.1 E 4.866(yo)-.15 G 2.366
+(ne le)406.406 273 R -.05(ga)-.15 G 4.866(lh).05 G 2.366(ost might be)449.818
+273 R(\231a.CC.Berk)117 285 Q(ele)-.1 E -.65(y.)-.15 G .366
+(EDU\232; reading from right to left, \231EDU\232 is a top le).65 F -.15(ve)
+-.25 G 2.865(ld).15 G .365(omain comprising edu-)410.5 285 R .561
+(cational institutions, \231Berk)117 297 R(ele)-.1 E .562
+(y\232 is a logical domain name, \231CC\232 represents the Computer Cen-)-.15 F
+(ter)117 309 Q 2.5(,\()-.4 G(in this case a strictly logical entity\), and \
+\231a\232 is a host in the Computer Center)135.48 309 Q(.)-.55 E(Be)142 325.2 Q
+-.1(wa)-.25 G(re when reading RFC819 that there are a number of errors in it.)
+.1 E F0 2.5(5.2.4. Ho)102 349.2 R 2.5(wt)-.1 G 2.5(op)155.23 349.2 S -.18(ro)
+168.29 349.2 S(ceed).18 E F1 .335(Once you ha)142 365.4 R .635 -.15(ve d)-.2 H
+.335(ecided on a philosoph).15 F 1.635 -.65(y, i)-.05 H 2.835(ti).65 G 2.834
+(sw)319.44 365.4 S .334(orth e)333.284 365.4 R .334(xamining the a)-.15 F -.25
+(va)-.2 G .334(ilable con\214guration).25 F .174(tables to decide if an)117
+377.4 R 2.674(yo)-.15 G 2.674(ft)212.98 377.4 S .174
+(hem are close enough to steal major parts of.)221.764 377.4 R(Ev)5.174 E .175
+(en under the w)-.15 F .175(orst of)-.1 F(conditions, there is a f)117 389.4 Q
+(air amount of boiler plate that can be collected safely)-.1 E(.)-.65 E .33
+(The ne)142 405.6 R .33(xt step is to b)-.15 F .33(uild ruleset three.)-.2 F
+.329(This will be the hardest part of the job)5.33 F 5.329(.B)-.4 G -2.1 -.25
+(ew a)469.321 405.6 T .329(re of).25 F .781
+(doing too much to the address in this ruleset, since an)117 417.6 R .781
+(ything you do will re\215ect through to the)-.15 F 2.744(message. In)117 429.6
+R(particular)2.744 E 2.744(,s)-.4 G .243
+(tripping of local domains is best deferred, since this can lea)216.752 429.6 R
+.543 -.15(ve y)-.2 H .243(ou with).15 F 1.234
+(addresses with no domain spec at all.)117 441.6 R(Since)6.235 E F2(sendmail)
+3.735 E F1(lik)3.735 E 1.235(es to append the sending domain to)-.1 F .83
+(addresses with no domain, this can change the semantics of addresses.)117
+453.6 R .83(Also try to a)5.83 F -.2(vo)-.2 G .83(id fully).2 F .342
+(qualifying domains in this ruleset.)117 465.6 R .342(Although technically le)
+5.342 F -.05(ga)-.15 G .343(l, this can lead to unpleasantly and).05 F 1.287
+(unnecessarily long addresses re\215ected into messages.)117 477.6 R 1.287
+(The Berk)6.287 F(ele)-.1 E 3.787(yc)-.15 G 1.287
+(on\214guration \214les de\214ne)406.426 477.6 R .093
+(ruleset nine to qualify domain names and strip local domains.)117 489.6 R .093
+(This is called from ruleset zero to)5.093 F
+(get all addresses into a cleaner form.)117 501.6 Q .318(Once you ha)142 517.8
+R .618 -.15(ve r)-.2 H .318
+(uleset three \214nished, the other rulesets should be relati).15 F -.15(ve)
+-.25 G .318(ly tri).15 F 2.817(vial. If)-.25 F(you)2.817 E(need hints, e)117
+529.8 Q(xamine the supplied con\214guration tables.)-.15 E F0 2.5(5.2.5. T)102
+553.8 R(esting the r)-.92 E(ewriting rules \212 the \255bt \215ag)-.18 E F1
+1.075(When you b)142 570 R 1.075(uild a con\214guration table, you can do a ce\
+rtain amount of testing using the)-.2 F(\231test mode\232 of)117 582 Q F2
+(sendmail)2.5 E F1 5(.F)C(or e)226.84 582 Q(xample, you could in)-.15 E -.2(vo)
+-.4 G -.1(ke).2 G F2(sendmail)2.6 E F1(as:)2.5 E(sendmail \255bt \255Ctest.cf)
+157 598.2 Q .904(which w)117 614.4 R .903
+(ould read the con\214guration \214le \231test.cf\232 and enter test mode.)-.1
+F .903(In this mode, you enter)5.903 F(lines of the form:)117 626.4 Q
+(rwset address)157 642.6 Q(where)117 658.8 Q F2(rwset)3.376 E F1 .876
+(is the re)3.376 F .876(writing set you w)-.25 F .876(ant to use and)-.1 F F2
+(addr)3.376 E(ess)-.37 E F1 .877(is an address to apply the set to.)3.376 F -.7
+(Te)117 670.8 S .17(st mode sho).7 F .17(ws you the steps it tak)-.25 F .169
+(es as it proceeds, \214nally sho)-.1 F .169(wing you the address it ends up)
+-.25 F 3.635(with. Y)117 682.8 R 1.135(ou may use a comma separated list of rw\
+sets for sequential application of rules to an)-1.1 F 2.5(input. F)117 694.8 R
+(or e)-.15 E(xample:)-.15 E(3,1,21,4 monet:bollard)157 711 Q EP
+%%Page: 45 40
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-45)452.9 60 Q/F1 10/Times-Roman@0 SF .386
+(\214rst applies ruleset three to the input \231monet:bollard.)117 96 R 5.385
+<9a52>-.7 G .385(uleset one is then applied to the output)347.145 96 R
+(of ruleset three, follo)117 108 Q
+(wed similarly by rulesets twenty-one and four)-.25 E(.)-.55 E .202(If you nee\
+d more detail, you can also use the \231\255d21\232 \215ag to turn on more deb)
+142 124.2 R 2.702(ugging. F)-.2 F(or)-.15 E -.15(ex)117 136.2 S(ample,).15 E
+(sendmail \255bt \255d21.99)157 152.4 Q .754
+(turns on an incredible amount of information; a single w)117 168.6 R .753
+(ord address is probably going to print)-.1 F(out se)117 180.6 Q -.15(ve)-.25 G
+(ral pages w).15 E(orth of information.)-.1 E -1.1(Yo)142 196.8 S 3.234(us)1.1
+G .734(hould be w)165.244 196.8 R .734(arned that internally)-.1 F(,)-.65 E/F2
+10/Times-Italic@0 SF(sendmail)3.234 E F1 .734
+(applies ruleset 3 to all addresses.)3.234 F .735(In this)5.735 F -.15(ve)117
+208.8 S 1.23(rsion of).15 F F2(sendmail)3.73 E F1 3.73(,y)C 1.23(ou will ha)
+209.42 208.8 R 1.53 -.15(ve t)-.2 H 3.73(od).15 G 3.73(ot)281.21 208.8 S 1.23
+(hat manually)292.72 208.8 R 6.23(.F)-.65 G 1.23(or e)359.38 208.8 R 1.23
+(xample, older v)-.15 F 1.23(ersions allo)-.15 F(wed)-.25 E(you to use)117
+220.8 Q 2.5(0b)157 237 S(ruce@broadcast.son)169.5 237 Q -.65(y.)-.15 G(com).65
+E(This v)117 253.2 Q(ersion requires that you use:)-.15 E
+(3,0 bruce@broadcast.son)157 269.4 Q -.65(y.)-.15 G(com).65 E F0 2.5
+(5.2.6. Building)102 297.6 R(mailer descriptions)2.5 E F1 1.886 -.8(To a)142
+313.8 T .287(dd an outgoing mailer to your mail system, you will ha).8 F .587
+-.15(ve t)-.2 H 2.787(od).15 G .287(e\214ne the characteristics)409.566 313.8 R
+(of the mailer)117 325.8 Q(.)-.55 E 1.481(Each mailer must ha)142 342 R 1.781
+-.15(ve a)-.2 H 3.981(ni).15 G 1.481(nternal name.)257.645 342 R 1.481
+(This can be arbitrary)6.481 F 3.98(,e)-.65 G 1.48(xcept that the names)417.63
+342 R(\231local\232 and \231prog\232 must be de\214ned.)117 354 Q .127
+(The pathname of the mailer must be gi)142 370.2 R -.15(ve)-.25 G 2.628(ni).15
+G 2.628(nt)317.038 370.2 S .128(he P \214eld.)327.446 370.2 R .128
+(If this mailer should be accessed)5.128 F
+(via an IPC connection, use the string \231[IPC]\232 instead.)117 382.2 Q .021
+(The F \214eld de\214nes the mailer \215ags.)142 398.4 R -1.1(Yo)5.021 G 2.521
+(us)1.1 G .021(hould specify an \231f\232 or \231r\232 \215ag to pass the name)
+311.06 398.4 R .465(of the sender as a)117 410.4 R F0<ad66>2.965 E F1(or)2.965
+E F0<ad72>2.965 E F1 .465(\215ag respecti)2.965 F -.15(ve)-.25 G(ly).15 E 5.465
+(.T)-.65 G .465(hese \215ags are only passed if the)306.95 410.4 R 2.966(yw)
+-.15 G .466(ere passed to)451.418 410.4 R F2(sendmail)117 422.4 Q F1 4.205(,s)C
+4.205(ot)163.705 422.4 S 1.705(hat mailers that gi)175.69 422.4 R 2.005 -.15
+(ve e)-.25 H 1.705(rrors under some circumstances can be placated.).15 F 1.705
+(If the)6.705 F 1.362(mailer is not pick)117 434.4 R 3.862(yy)-.15 G 1.362
+(ou can just specify \231\255f $g\232 in the ar)204.518 434.4 R 1.362
+(gv template.)-.18 F 1.363(If the mailer must be)6.362 F 1.708(called as)117
+446.4 R F0 -.18(ro)4.207 G(ot).18 E F1 1.707(the \231S\232 \215ag should be gi)
+4.207 F -.15(ve)-.25 G 1.707
+(n; this will not reset the userid before calling the).15 F(mailer)117 460.4 Q
+/F3 7/Times-Roman@0 SF(16)142.55 456.4 Q F1 5.112(.I)149.55 460.4 S 2.612(ft)
+160.492 460.4 S .112(his mailer is local \(i.e., will perform \214nal deli)
+169.214 460.4 R -.15(ve)-.25 G .112(ry rather than another netw).15 F .112
+(ork hop\))-.1 F .728(the \231l\232 \215ag should be gi)117 472.4 R -.15(ve)
+-.25 G 3.227(n. Quote).15 F .727
+(characters \(backslashes and " marks\) can be stripped from)3.227 F .268
+(addresses if the \231s\232 \215ag is speci\214ed; if this is not gi)117 484.4
+R -.15(ve)-.25 G 2.769(nt).15 G(he)344.247 484.4 Q 2.769(ya)-.15 G .269
+(re passed through.)365.746 484.4 R .269(If the mailer is)5.269 F .67(capable \
+of sending to more than one user on the same host in a single transaction the \
+\231m\232 \215ag)117 496.4 R 1.176(should be stated.)117 508.4 R 1.176
+(If this \215ag is on, then the ar)6.176 F 1.177(gv template containing)-.18 F
+F0($u)3.677 E F1 1.177(will be repeated for)3.677 F .089
+(each unique user on a gi)117 520.4 R -.15(ve)-.25 G 2.589(nh).15 G 2.589
+(ost. The)235.994 520.4 R .089
+(\231e\232 \215ag will mark the mailer as being \231e)2.589 F(xpensi)-.15 E
+-.15(ve)-.25 G 1.488 -.7(,\232 w).15 H(hich).7 E(will cause)117 534.4 Q F2
+(sendmail)2.5 E F1(to defer connection until a queue run)2.5 E F3(17)345.57
+530.4 Q F1(.)352.57 534.4 Q 2.037(An unusual case is the \231C\232 \215ag.)142
+550.6 R 2.037(This \215ag applies to the mailer that the message is)7.037 F
+(recei)117 562.6 Q -.15(ve)-.25 G 2.654(df).15 G .153(rom, rather than the mai\
+ler being sent to; if set, the domain spec of the sender \(i.e., the)156.454
+562.6 R 1.519(\231@host.domain\232 part\) is sa)117 574.6 R -.15(ve)-.2 G 4.019
+(da).15 G 1.519(nd is appended to an)252.746 574.6 R 4.019(ya)-.15 G 1.52
+(ddresses in the message that do not)354.341 574.6 R
+(already contain a domain spec.)117 586.6 Q -.15(Fo)5 G 2.5(re).15 G
+(xample, a message of the form:)266.11 586.6 Q(From: eric@v)157 602.8 Q
+(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E -.8(To)157 614.8 S
+2.5(:w).8 G(nj@monet.CS.Berk)179.81 614.8 Q(ele)-.1 E -.65(y.)-.15 G
+(EDU, mckusick).65 E(will be modi\214ed to:)117 631 Q .32 LW 76 665.2 72 665.2
+DL 80 665.2 76 665.2 DL 84 665.2 80 665.2 DL 88 665.2 84 665.2 DL 92 665.2 88
+665.2 DL 96 665.2 92 665.2 DL 100 665.2 96 665.2 DL 104 665.2 100 665.2 DL 108
+665.2 104 665.2 DL 112 665.2 108 665.2 DL 116 665.2 112 665.2 DL 120 665.2 116
+665.2 DL 124 665.2 120 665.2 DL 128 665.2 124 665.2 DL 132 665.2 128 665.2 DL
+136 665.2 132 665.2 DL 140 665.2 136 665.2 DL 144 665.2 140 665.2 DL 148 665.2
+144 665.2 DL 152 665.2 148 665.2 DL 156 665.2 152 665.2 DL 160 665.2 156 665.2
+DL 164 665.2 160 665.2 DL 168 665.2 164 665.2 DL 172 665.2 168 665.2 DL 176
+665.2 172 665.2 DL 180 665.2 176 665.2 DL 184 665.2 180 665.2 DL 188 665.2 184
+665.2 DL 192 665.2 188 665.2 DL 196 665.2 192 665.2 DL 200 665.2 196 665.2 DL
+204 665.2 200 665.2 DL 208 665.2 204 665.2 DL 212 665.2 208 665.2 DL 216 665.2
+212 665.2 DL/F4 5/Times-Roman@0 SF(16)93.6 675.6 Q/F5 8/Times-Italic@0 SF
+(Sendmail)3.2 I/F6 8/Times-Roman@0 SF
+(must be running setuid to root for this to w)2 E(ork.)-.08 E F4(17)93.6 689.2
+Q F6(The \231c\232 con\214guration option must be gi)3.2 I -.12(ve)-.2 G 2(nf)
+.12 G(or this to be ef)242.04 692.4 Q(fecti)-.2 E -.12(ve)-.2 G(.).12 E EP
+%%Page: 46 41
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-46 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(From: eric@v)157
+96 Q(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E -.8(To)157 108 S
+2.5(:w).8 G(nj@monet.CS.Berk)179.81 108 Q(ele)-.1 E -.65(y.)-.15 G
+(EDU, mckusick@v).65 E(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E
+/F2 10/Times-Italic@0 SF 6.608(if and only if)117 124.2 R F1 6.607
+(the \231C\232 \215ag is de\214ned in the mailer resolv)9.108 F 6.607
+(ed to by running)-.15 F(\231eric@v)117 136.2 Q(angogh.CS.Berk)-.25 E(ele)-.1 E
+-.65(y.)-.15 G(EDU\232 through rulesets 3 and 0.).65 E
+(Other \215ags are described in Appendix C.)142 152.4 Q .538
+(The S and R \214elds in the mailer description are per)142 168.6 R .538
+(-mailer re)-.2 F .538(writing sets to be applied to)-.25 F 2.253
+(sender and recipient addresses respecti)117 180.6 R -.15(ve)-.25 G(ly).15 E
+7.253(.T)-.65 G 2.252(hese are applied after the sending domain is)312.995
+180.6 R .546(appended and the general re)117 192.6 R .547
+(writing sets \(numbers one and tw)-.25 F .547(o\) are applied, b)-.1 F .547
+(ut before the out-)-.2 F .458(put re)117 204.6 R .458
+(write \(ruleset four\) is applied.)-.25 F 2.958(At)5.458 G .457
+(ypical use is to append the current domain to addresses)279.646 204.6 R
+(that do not already ha)117 216.6 Q .3 -.15(ve a d)-.2 H 2.5(omain. F).15 F
+(or e)-.15 E(xample, a header of the form:)-.15 E(From: eric)157 232.8 Q
+(might be changed to be:)117 249 Q(From: eric@v)157 265.2 Q(angogh.CS.Berk)-.25
+E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E(or)117 281.4 Q(From: ucb)157 297.6 Q -.25
+(va)-.15 G(x!eric).25 E .186(depending on the domain it is being shipped into.)
+117 313.8 R .186(These sets can also be used to do special pur)5.186 F(-)-.2 E
+(pose output re)117 325.8 Q(writing in cooperation with ruleset four)-.25 E(.)
+-.55 E .026(The S and R \214elds can be speci\214ed as tw)142 342 R 2.526(on)
+-.1 G .025(umbers separated by a slash \(e.g., \231S=10/11\232\),)318.25 342 R
+2.915(meaning that all en)117 354 R -.15(ve)-.4 G 2.915
+(lope addresses will be processed through ruleset 10 and all header).15 F .403
+(addresses will be processed through ruleset 11.)117 366 R -.4(Wi)5.402 G .402
+(th only one number speci\214ed, both en).4 F -.15(ve)-.4 G(lope).15 E
+(and header re)117 378 Q(writing sets are set to the indicated ruleset.)-.25 E
+.228(The E \214eld de\214nes the string to use as an end-of-line indication.)
+142 394.2 R 2.728(As)5.228 G .228(tring containing only)419.654 394.2 R(ne)117
+406.2 Q(wline is the def)-.25 E 2.5(ault. The)-.1 F
+(usual backslash escapes \(\\r)2.5 E 2.5(,\\)-.4 G(n, \\f, \\b\) may be used.)
+342.87 406.2 Q(Finally)142 422.4 Q 2.584(,a)-.65 G 2.584(na)179.214 422.4 S
+-.18(rg)191.238 422.4 S 2.584(vt).18 G .084(emplate is gi)209.752 422.4 R -.15
+(ve)-.25 G 2.584(na).15 G 2.584(st)282.094 422.4 S .084(he A \214eld.)291.348
+422.4 R .083(It may ha)5.083 F .383 -.15(ve e)-.2 H .083(mbedded spaces.).15 F
+.083(If there is)5.083 F .203(no ar)117 434.4 R .203(gv with a)-.18 F F0($u)
+2.703 E F1 .203(macro in it,)2.703 F F2(sendmail)2.704 E F1 .204
+(will speak SMTP to the mailer)2.704 F 5.204(.I)-.55 G 2.704(ft)412.644 434.4 S
+.204(he pathname for this)421.458 434.4 R(mailer is \231[IPC],)117 446.4 Q 2.5
+<9a74>-.7 G(he ar)192.4 446.4 Q(gv should be)-.18 E(IPC $h [)157 462.6 Q F2
+(port)2.5 E F1(])2.5 E(where)117 478.8 Q F2(port)2.5 E F1
+(is the optional port number to connect to.)2.5 E -.15(Fo)142 495 S 2.5(re).15
+G(xample, the speci\214cations:)162.53 495 Q(Mlocal, P=/bin/mail, F=rlsm)157
+511.2 Q(S=10, R=20, A=mail \255d $u)5 E(Mether)157 523.2 Q 2.35(,P)-.4 G 13.9
+(=[IPC], F=meC,)195.89 523.2 R(S=11, R=21, A=IPC $h, M=100000)1.39 E 1.644
+(speci\214es a mailer to do local deli)117 539.4 R -.15(ve)-.25 G 1.644
+(ry and a mailer for ethernet deli).15 F -.15(ve)-.25 G(ry).15 E 6.643(.T)-.65
+G 1.643(he \214rst is called)436.021 539.4 R(\231local,)117 551.4 Q 2.648<9a69>
+-.7 G 2.648(sl)152.548 551.4 S .148(ocated in the \214le \231/bin/mail,)161.866
+551.4 R 2.649<9a74>-.7 G(ak)283.569 551.4 Q .149(es a pick)-.1 F(y)-.15 E F0
+<ad72>2.649 E F1 .149(\215ag, does local deli)2.649 F -.15(ve)-.25 G(ry).15 E
+2.649(,q)-.65 G .149(uotes should)453.571 551.4 R 1.017
+(be stripped from addresses, and multiple users can be deli)117 563.4 R -.15
+(ve)-.25 G 1.016(red at once; ruleset ten should be).15 F 1.417(applied to sen\
+der addresses in the message and ruleset twenty should be applied to recipient)
+117 575.4 R .123(addresses; the ar)117 587.4 R .123
+(gv to send to a message will be the w)-.18 F .123(ord \231mail,)-.1 F 2.623
+<9a74>-.7 G .123(he w)383.129 587.4 R .122(ord \231\255d,)-.1 F 2.622<9a61>-.7
+G .122(nd w)446.646 587.4 R .122(ords con-)-.1 F 1.484
+(taining the name of the recei)117 599.4 R 1.484(ving user)-.25 F 6.484(.I)-.55
+G 3.984(fa)288.496 599.4 S F0<ad72>A F1 1.484
+(\215ag is inserted it will be between the w)3.984 F(ords)-.1 E .289
+(\231mail\232 and \231\255d.)117 611.4 R 5.289<9a54>-.7 G .289
+(he second mailer is called \231ether)196.397 611.4 R 1.689 -.7(,\232 i)-.4 H
+2.789(ts).7 G .289(hould be connected to via an IPC con-)348.95 611.4 R .932(n\
+ection, it can handle multiple users at once, connections should be deferred, \
+and an)117 623.4 R 3.433(yd)-.15 G(omain)479 623.4 Q 1.458
+(from the sender address should be appended to an)117 635.4 R 3.958(yr)-.15 G
+(ecei)340.202 635.4 Q -.15(ve)-.25 G 3.958(rn).15 G 1.458
+(ame without a domain; sender)377.63 635.4 R .74
+(addresses should be processed by ruleset ele)117 647.4 R -.15(ve)-.25 G 3.24
+(na).15 G .74(nd recipient addresses by ruleset twenty-one.)320.34 647.4 R
+(There is a 100,000 byte limit on messages passed through this mailer)117 659.4
+Q(.)-.55 E F0 2.5(5.3. The)87 683.4 R(User Database)2.5 E F1 .109(If you ha)127
+699.6 R .409 -.15(ve a ve)-.2 H .109(rsion of).15 F F2(sendmail)2.609 E F1 .109
+(with the user database package compiled in, the handling of)2.609 F
+(sender and recipient addresses is modi\214ed.)102 711.6 Q EP
+%%Page: 47 42
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-47)452.9 60 Q/F1 10/Times-Roman@0 SF
+(The location of this database is controlled with the)127 96 Q F0(U)2.5 E F1
+(option.)2.5 E F0 2.5(5.3.1. Structur)102 120 R 2.5(eo)-.18 G 2.5(ft)177.92 120
+S(he user database)187.08 120 Q F1(The database is a sorted \(BT)142 136.2 Q
+(ree-based\) structure.)-.35 E(User records are stored with the k)5 E -.15(ey)
+-.1 G(:).15 E/F2 10/Times-Italic@0 SF(user)157 152.4 Q(-name)-.2 E F0(:)A F2
+(\214eld-name)A F1 .128
+(The sorted database format ensures that user records are clustered together)
+117 168.6 R 5.129(.M)-.55 G .129(eta-information is)432.491 168.6 R(al)117
+180.6 Q -.1(wa)-.1 G(ys stored with a leading colon.).1 E
+(Field names de\214ne both the syntax and semantics of the v)142 196.8 Q 2.5
+(alue. De\214ned)-.25 F(\214elds include:)2.5 E 33.39(maildrop The)117 213 R
+(deli)4.873 E -.15(ve)-.25 G 2.373(ry address for this user).15 F 7.373(.T)-.55
+G 2.372(here may be multiple v)349.478 213 R 2.372(alues of this)-.25 F 2.675
+(record. In)189 225 R(particular)2.675 E 2.675(,m)-.4 G .175
+(ailing lists will ha)284.095 225 R .475 -.15(ve o)-.2 H(ne).15 E F2(maildr)
+2.675 E(op)-.45 E F1 .175(record for each user)2.675 F(on the list.)189 237 Q
+30.06(mailname The)117 253.2 R 1.027(outgoing mailname for this user)3.527 F
+6.026(.F)-.55 G 1.026(or each outgoing name, there should)353.34 253.2 R .08
+(be an appropriate)189 265.2 R F2(maildr)2.58 E(op)-.45 E F1 .08
+(record for that name to allo)2.58 F 2.58(wr)-.25 G .08(eturn mail.)422.38
+265.2 R .08(See also)5.08 F F2(:default:mailname)189 277.2 Q F1(.)A 25.62
+(mailsender Changes)117 293.4 R(an)3.448 E 3.448(ym)-.15 G .948
+(ail sent to this address to ha)252.406 293.4 R 1.247 -.15(ve t)-.2 H .947
+(he indicated en).15 F -.15(ve)-.4 G .947(lope sender).15 F(.)-.55 E .498(This\
+ is intended for mailing lists, and will normally be the name of an appro-)189
+305.4 R .755(priate -request address.)189 317.4 R .755(It is v)5.755 F .755
+(ery similar to the o)-.15 F(wner)-.25 E(-)-.2 E F2(list)A F1 .754
+(syntax in the alias)3.254 F(\214le.)189 329.4 Q 33.95(fullname The)117 345.6 R
+(full name of the user)2.5 E(.)-.55 E(of)117 361.8 Q 13.66(\214ce-address The)
+-.25 F(of)2.5 E(\214ce address for this user)-.25 E(.)-.55 E(of)117 378 Q 19.21
+(\214ce-phone The)-.25 F(of)2.5 E(\214ce phone number for this user)-.25 E(.)
+-.55 E(of)117 394.2 Q(\214ce-f)-.25 E 30.98(ax The)-.1 F(of)2.5 E(\214ce F)-.25
+E(AX number for this user)-.74 E(.)-.55 E 13.96(home-address The)117 410.4 R
+(home address for this user)2.5 E(.)-.55 E 19.51(home-phone The)117 426.6 R
+(home phone number for this user)2.5 E(.)-.55 E(home-f)117 442.8 Q 31.28
+(ax The)-.1 F(home F)2.5 E(AX number for this user)-.74 E(.)-.55 E 41.73
+(project A)117 459 R .855
+(\(short\) description of the project this person is af)3.355 F .856
+(\214liated with.)-.25 F .856(In the Uni-)5.856 F -.15(ve)189 471 S
+(rsity this is often just the name of their graduate advisor).15 E(.)-.55 E
+52.28(plan A)117 487.2 R
+(pointer to a \214le from which plan information can be g)2.5 E(athered.)-.05 E
+.925(As of this writing, only a fe)142 503.4 R 3.424(wo)-.25 G 3.424(ft)273.214
+503.4 S .924(hese \214elds are actually being used by)282.748 503.4 R F2
+(sendmail)3.424 E F1(:)A F2(mail-)3.424 E(dr)117 515.4 Q(op)-.45 E F1(and)2.5 E
+F2(mailname)2.5 E F1 5(.A)C F2(\214ng)211.54 515.4 Q(er)-.1 E F1
+(program that uses the other \214elds is planned.)2.5 E F0 2.5(5.3.2. User)102
+539.4 R(database semantics)2.5 E F1 .995(When the re)142 555.6 R .995
+(writing rules submit an address to the local mailer)-.25 F 3.496(,t)-.4 G .996
+(he user name is passed)408.926 555.6 R .781(through the alias \214le.)117
+567.6 R .78
+(If no alias is found \(or if the alias points back to the same address\), the)
+5.781 F 1.777(name \(with \231:maildrop\232 appended\) is then used as a k)117
+579.6 R 2.078 -.15(ey i)-.1 H 4.278(nt).15 G 1.778(he user database.)375.98
+579.6 R 1.778(If no match)6.778 F
+(occurs \(or if the maildrop points at the same address\), forw)117 591.6 Q
+(arding is tried.)-.1 E .551(If the \214rst tok)142 607.8 R .55(en of the user\
+ name returned by ruleset 0 is an \231@\232 sign, the user database)-.1 F .625
+(lookup is skipped.)117 619.8 R .625
+(The intent is that the user database will act as a set of def)5.625 F .626
+(aults for a cluster)-.1 F 1.533(\(in our case, the Computer Science Di)117
+631.8 R 1.533(vision\); mail sent to a speci\214c machine should ignore)-.25 F
+(these def)117 643.8 Q(aults.)-.1 E .351
+(When mail is sent, the name of the sending user is look)142 660 R .351
+(ed up in the database.)-.1 F .352(If that user)5.351 F .041
+(has a \231mailname\232 record, the v)117 672 R .041
+(alue of that record is used as their outgoing name.)-.25 F -.15(Fo)5.04 G 2.54
+(re).15 G .04(xample, I)466.19 672 R(might ha)117 684 Q .3 -.15(ve a r)-.2 H
+(ecord:).15 E 25.94(eric:mailname Eric.Allman@CS.Berk)157 700.2 R(ele)-.1 E
+-.65(y.)-.15 G(EDU).65 E(This w)117 716.4 Q
+(ould cause my outgoing mail to be sent as Eric.Allman.)-.1 E EP
+%%Page: 48 43
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-48 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF .519
+(If a \231maildrop\232 is found for the user)142 96 R 3.019(,b)-.4 G .52
+(ut no corresponding \231mailname\232 record e)299.682 96 R .52(xists, the)-.15
+F 1.128(record \231:def)117 108 R 1.128(ault:mailname\232 is consulted.)-.1 F
+1.127(If present, this is the name of a host to o)6.128 F -.15(ve)-.15 G 1.127
+(rride the).15 F .625(local host.)117 120 R -.15(Fo)5.625 G 3.125(re).15 G .625
+(xample, in our case we w)185.515 120 R .625(ould set it to \231CS.Berk)-.1 F
+(ele)-.1 E -.65(y.)-.15 G 3.125(EDU\232. The).65 F(ef)3.125 E .625
+(fect is that)-.25 F(an)117 132 Q .882(yone kno)-.15 F .882
+(wn in the database gets their outgoing mail stamped as \231user@CS.Berk)-.25 F
+(ele)-.1 E -.65(y.)-.15 G(EDU\232,).65 E -.2(bu)117 144 S 2.5(tp).2 G
+(eople not listed in the database use the local hostname.)137.08 144 Q F0 2.5
+(5.3.3. Cr)102 170 R(eating the database)-.18 E/F2 7/Times-Bold@0 SF(18)223.2
+166 Q F1 .375(The user database is b)142 186.2 R .375(uilt from a te)-.2 F .375
+(xt \214le using the)-.15 F/F3 10/Times-Italic@0 SF(mak)2.875 E(emap)-.1 E F1
+.375(utility \(in the distrib)2.875 F .375(ution in)-.2 F 1.038(the mak)117
+198.2 R 1.038(emap subdirectory\).)-.1 F 1.038(The te)6.038 F 1.039
+(xt \214le is a series of lines corresponding to userdb records;)-.15 F 1.589
+(each line has a k)117 210.2 R 1.889 -.15(ey a)-.1 H 1.589(nd a v).15 F 1.589
+(alue separated by white space.)-.25 F 1.589(The k)6.589 F 1.889 -.15(ey i)-.1
+H 4.089(sa).15 G -.1(lwa)421.945 210.2 S 1.588(ys in the format).1 F
+(described abo)117 222.2 Q .3 -.15(ve \212 f)-.15 H(or e).15 E(xample:)-.15 E
+(eric:maildrop)157 238.4 Q .447
+(This \214le is normally installed in a system directory; for e)117 254.6 R
+.448(xample, it might be called)-.15 F F3(/etc/user)2.948 E(db)-.37 E F1(.)A
+1.6 -.8(To m)117 266.6 T(ak).8 E 2.5(et)-.1 G(he database v)156.65 266.6 Q
+(ersion of the map, run the program:)-.15 E(mak)157 282.8 Q
+(emap btree /etc/userdb)-.1 E(.db < /etc/userdb)-.4 E .077
+(Then create a con\214g \214le that uses this.)117 299 R -.15(Fo)5.077 G 2.577
+(re).15 G .077(xample, using the V8 M4 con\214guration, include the)296.533 299
+R(follo)117 311 Q(wing line in your .mc \214le:)-.25 E
+(de\214ne\(\222confUSERDB_SPEC\264, /etc/userdb)157 327.2 Q(.db\))-.4 E F0 2.5
+(6. O)72 355.4 R(THER CONFIGURA)-.4 E(TION)-.95 E F1 .907
+(There are some con\214guration changes that can be made by recompiling)112
+371.6 R F3(sendmail)3.407 E F1 5.907(.T)C .907(his section)460.593 371.6 R
+(describes what changes can be made and what has to be modi\214ed to mak)87
+383.6 Q 2.5(et)-.1 G(hem.)387.95 383.6 Q F0 2.5(6.1. P)87 407.6 R
+(arameters in sr)-.1 E(c/Mak)-.18 E(e\214le)-.1 E F1 .92
+(These parameters are intended to describe the compilation en)127 423.8 R .92
+(vironment, not site polic)-.4 F 2.22 -.65(y, a)-.15 H(nd).65 E
+(should normally be de\214ned in src/Mak)102 435.8 Q(e\214le.)-.1 E 39.5
+(NDBM If)102 452 R .664(set, the ne)3.164 F 3.164(wv)-.25 G .664
+(ersion of the DBM library that allo)240.406 452 R .665
+(ws multiple databases will be)-.25 F 2.543(used. If)174 464 R .042
+(neither NDBM nor NEWDB are set, a much less ef)2.543 F .042
+(\214cient method of alias)-.25 F(lookup is used.)174 476 Q 32.84(NEWDB If)102
+492.2 R .141(set, use the ne)2.641 F 2.642(wd)-.25 G .142
+(atabase package from Berk)254.436 492.2 R(ele)-.1 E 2.642(y\()-.15 G .142
+(from 4.4BSD\).)385.814 492.2 R .142(This package)5.142 F .267
+(is substantially f)174 504.2 R .267(aster than DBM or NDBM.)-.1 F .267
+(If NEWDB and NDBM are both set,)5.267 F F3(sendmail)174 516.2 Q F1
+(will read DBM \214les, b)2.5 E(ut will create and use NEWDB \214les.)-.2 E
+53.39(NIS Include)102 532.4 R .119(support for NIS.)2.619 F .119
+(If set together with)5.119 F F3(both)2.619 E F1 .119(NEWDB and NDBM,)2.619 F
+F3(sendmail)2.62 E F1 1.076
+(will create both DBM and NEWDB \214les if and only if the \214le /v)174 544.4
+R(ar/yp/Mak)-.25 E(e\214le)-.1 E -.15(ex)174 556.4 S .292
+(ists and is readable.).15 F .293
+(This is intended for compatibility with Sun Microsystems')5.293 F F3(mkalias)
+174 568.4 Q F1(program used on YP masters.)2.5 E 25.05(SYSTEM5 Set)102 584.6 R
+(all of the compilation parameters appropriate for System V)2.5 E(.)-1.29 E
+36.72(LOCKF Use)102 600.8 R .3(System V)2.8 F F0(lockf)2.8 E F1 .299
+(instead of Berk)2.799 F(ele)-.1 E(y)-.15 E F0(\215ock)2.799 E F1 5.299(.D)C
+.299(ue to the highly unusual seman-)375.015 600.8 R .051
+(tics of locks across forks in)174 612.8 R F0(lockf)2.551 E F1 2.551(,t)C .051
+(his should ne)314.897 612.8 R -.15(ve)-.25 G 2.552(rb).15 G 2.552(eu)387.702
+612.8 S .052(sed unless absolutely nec-)399.694 612.8 R(essary)174 624.8 Q 5
+(.S)-.65 G(et by def)211.4 624.8 Q(ault if SYSTEM5 is set.)-.1 E 33.94
+(SYS5TZ Use)102 641 R(System V time zone semantics.)2.5 E(HASINITGR)102 657.2 Q
+(OUPS)-.4 E 2.392(Set this if your system has the)174 669.2 R F3(initgr)4.892 E
+(oups\(\))-.45 E F1 2.391(call \(if you ha)4.891 F 2.691 -.15(ve m)-.2 H 2.391
+(ultiple group).15 F .32 LW 76 678.8 72 678.8 DL 80 678.8 76 678.8 DL 84 678.8
+80 678.8 DL 88 678.8 84 678.8 DL 92 678.8 88 678.8 DL 96 678.8 92 678.8 DL 100
+678.8 96 678.8 DL 104 678.8 100 678.8 DL 108 678.8 104 678.8 DL 112 678.8 108
+678.8 DL 116 678.8 112 678.8 DL 120 678.8 116 678.8 DL 124 678.8 120 678.8 DL
+128 678.8 124 678.8 DL 132 678.8 128 678.8 DL 136 678.8 132 678.8 DL 140 678.8
+136 678.8 DL 144 678.8 140 678.8 DL 148 678.8 144 678.8 DL 152 678.8 148 678.8
+DL 156 678.8 152 678.8 DL 160 678.8 156 678.8 DL 164 678.8 160 678.8 DL 168
+678.8 164 678.8 DL 172 678.8 168 678.8 DL 176 678.8 172 678.8 DL 180 678.8 176
+678.8 DL 184 678.8 180 678.8 DL 188 678.8 184 678.8 DL 192 678.8 188 678.8 DL
+196 678.8 192 678.8 DL 200 678.8 196 678.8 DL 204 678.8 200 678.8 DL 208 678.8
+204 678.8 DL 212 678.8 208 678.8 DL 216 678.8 212 678.8 DL/F4 5/Times-Roman@0
+SF(18)93.6 689.2 Q/F5 8/Times-Roman@0 SF .288(These instructions are kno)3.2 J
+.289(wn to be incomplete.)-.2 F 2.289(Af)4.289 G .289(uture v)266.46 692.4 R
+.289(ersion of the user database is planned including things such as \214n-)
+-.12 F(ger service \212 and good documentation.)72 702 Q EP
+%%Page: 49 44
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-49)452.9 60 Q/F1 10/Times-Roman@0 SF 2.5(support\). This)174 96 R
+(is the def)2.5 E(ault if SYSTEM5 is)-.1 E/F2 10/Times-Italic@0 SF(not)2.5 E F1
+(de\214ned or if you are on HPUX.)2.5 E(HASUN)102 112.2 Q 13.19(AME Set)-.35 F
+.89(this if you ha)3.39 F 1.19 -.15(ve t)-.2 H(he).15 E F2(uname)3.39 E F1 .89
+(\(2\) system call \(or corresponding library routine\).)B(Set by def)174 124.2
+Q(ault if SYSTEM5 is set.)-.1 E(HASST)102 140.4 Q -1.11(AT)-.93 G 15.42(FS Set)
+1.11 F .202(this if you ha)2.702 F .502 -.15(ve t)-.2 H(he).15 E F2(statfs)
+2.702 E F1 .202(\(2\) system call.)B .202(This will allo)5.202 F 2.702(wy)-.25
+G .202(ou to gi)425.824 140.4 R .501 -.15(ve a t)-.25 H(empo-).15 E .107
+(rary f)174 152.4 R .108(ailure message to incoming SMTP email when you are lo)
+-.1 F 2.608(wo)-.25 G 2.608(nd)441.186 152.4 S .108(isk space.)453.794 152.4 R
+(It)5.108 E(is set by def)174 164.4 Q(ault on 4.4BSD and OSF/1 systems.)-.1 E
+(HASUST)102 180.6 Q 21.54 -1.11(AT S)-.93 H .594(et if you ha)1.11 F .894 -.15
+(ve t)-.2 H(he).15 E F2(ustat)3.094 E F1 .594(\(2\) system call.)B .594
+(This is an alternati)5.594 F .893 -.15(ve i)-.25 H .593(mplementation of).15 F
+.525(disk space control.)174 192.6 R -1.1(Yo)5.525 G 3.025(us)1.1 G .525
+(hould only set one of HASST)278.32 192.6 R -1.11(AT)-.93 G .525(FS or HASUST)
+1.11 F -.83 -1.11(AT ;)-.93 H(the)4.135 E(\214rst is preferred.)174 204.6 Q(_P)
+102 220.8 Q -1.11(AT)-.92 G(H_SENDMAILCF)1.11 E
+(The pathname of the sendmail.cf \214le.)174 232.8 Q(_P)102 249 Q -1.11(AT)-.92
+G(H_SENDMAILPID)1.11 E(The pathname of the sendmail.pid \214le.)174 261 Q 26.17
+(LA_TYPE The)102 277.2 R(load a)2.5 E -.15(ve)-.2 G(rage type.).15 E
+(Details are described belo)5 E -.65(w.)-.25 G .343(The are se)102 293.4 R -.15
+(ve)-.25 G .342(ral b).15 F .342(uilt-in w)-.2 F .342
+(ays of computing the load a)-.1 F -.15(ve)-.2 G(rage.).15 E F2(Sendmail)5.342
+E F1 .342(tries to auto-con\214gure them)2.842 F .266
+(based on imperfect guesses; you can select one using the)102 305.4 R F2(cc)
+2.767 E F1(option)2.767 E F0(\255DLA_TYPE=)2.767 E F2(type)A F1 2.767(,w)C
+(here)467.363 305.4 Q F2(type)2.767 E F1(is:)102 317.4 Q 34.51(LA_INT The)102
+333.6 R -.1(ke)2.979 G .479(rnel stores the load a).1 F -.15(ve)-.2 G .479
+(rage in the k).15 F .478(ernel as an array of long inte)-.1 F 2.978(gers. The)
+-.15 F(actual v)174 345.6 Q(alues are scaled by a f)-.25 E(actor FSCALE \(def)
+-.1 E(ault 256\).)-.1 E(LA_SHOR)102 361.8 Q 21.49(TT)-.6 G .33(he k)180.11
+361.8 R .33(ernel stores the load a)-.1 F -.15(ve)-.2 G .331(rage in the k).15
+F .331(ernel as an array of short inte)-.1 F 2.831(gers. The)-.15 F(actual v)
+174 373.8 Q(alues are scaled by a f)-.25 E(actor FSCALE \(def)-.1 E
+(ault 256\).)-.1 E(LA_FLO)102 390 Q 22.63 -1.11(AT T)-.35 H 1.118(he k)1.11 F
+1.117(ernel stores the load a)-.1 F -.15(ve)-.2 G 1.117(rage in the k).15 F
+1.117(ernel as an array of double precision)-.1 F(\215oats.)174 402 Q(LA_MA)102
+418.2 Q 21.57(CH Use)-.4 F(MA)2.5 E(CH-style load a)-.4 E -.15(ve)-.2 G(rages.)
+.15 E 25.05(LA_SUBR Call)102 434.4 R(the)2.5 E F2 -.1(ge)2.5 G(tloadavg).1 E F1
+(routine to get the load a)2.5 E -.15(ve)-.2 G(rage as an array of doubles.).15
+E(LA_ZER)102 450.6 Q 27.96(OA)-.4 G -.1(lwa)181.22 450.6 S
+(ys return zero as the load a).1 E -.15(ve)-.2 G 2.5(rage. This).15 F(is the f)
+2.5 E(allback case.)-.1 E .493(If type)102 466.8 R/F3 9/Times-Roman@0 SF
+(LA_INT)2.993 E F1(,)A F3(LA_SHOR)2.993 E(T)-.54 E F1 2.993(,o)C(r)224.802
+466.8 Q F3(LA_FLO)2.993 E -.999(AT)-.315 G F1 .493
+(is speci\214ed, you may also need to specify)3.992 F F3(_P)2.994 E -.999(AT)
+-.828 G(H_UNIX).999 E F1 .949(\(the path to your system binary\) and)102 478.8
+R F3(LA_A)3.448 E(VENR)-1.215 E(UN)-.36 E F1 .948(\(the name of the v)3.448 F
+.948(ariable containing the load)-.25 F -2.25 -.2(av e)102 490.8 T
+(rage in the k).2 E(ernel; usually \231_a)-.1 E -.15(ve)-.2 G
+(nrun\232 or \231a).15 E -.15(ve)-.2 G(nrun\232\).).15 E 1.439
+(There are also se)127 507 R -.15(ve)-.25 G 1.439
+(ral compilation \215ags to indicate the en).15 F 1.44
+(vironment such as \231_AIX3\232 and)-.4 F 2.5(\231_SCO_unix_\232. See)102 519
+R(the READ_ME \214le for the latest scoop on these \215ags.)2.5 E F0 2.5
+(6.2. P)87 543 R(arameters in sr)-.1 E(c/conf)-.18 E(.h)-.15 E F1 -.15(Pa)127
+559.2 S .896(rameters and compilation options are de\214ned in conf.h.).15 F
+.895(Most of these need not normally)5.895 F .192(be tweak)102 571.2 R .192
+(ed; common parameters are all in sendmail.cf.)-.1 F(Ho)5.192 E(we)-.25 E -.15
+(ve)-.25 G .992 -.4(r, t).15 H .192(he sizes of certain primiti).4 F .493 -.15
+(ve ve)-.25 H(c-).15 E(tors, etc., are included in this \214le.)102 583.2 Q
+(The numbers follo)5 E(wing the parameters are their def)-.25 E(ault v)-.1 E
+(alue.)-.25 E 1.91(MAXLINE [1024])102 599.4 R 1.909
+(The maximum line length of an)190.31 599.4 R 4.409(yi)-.15 G 1.909(nput line.)
+338.276 599.4 R 1.909(If message lines e)6.909 F 1.909(xceed this)-.15 F .575
+(length the)188.4 611.4 R 3.075(yw)-.15 G .575
+(ill still be processed correctly; ho)243.84 611.4 R(we)-.25 E -.15(ve)-.25 G
+1.375 -.4(r, h).15 H .575(eader lines, con\214gura-).4 F
+(tion \214le lines, alias lines, etc., must \214t within this limit.)188.4
+623.4 Q(MAXN)102 639.6 Q(AME [256])-.35 E(The maximum length of an)9.82 E 2.5
+(yn)-.15 G(ame, such as a host or a user name.)309.63 639.6 Q .231(MAXPV [40])
+102 655.8 R .231(The maximum number of parameters to an)188.631 655.8 R 2.731
+(ym)-.15 G(ailer)376.458 655.8 Q 5.231(.T)-.55 G .23(his limits the number of)
+407.519 655.8 R .375(recipients that may be passed in one transaction.)188.4
+667.8 R .376(It can be set to an)5.376 F 2.876(ya)-.15 G(rbitrary)474.01 667.8
+Q .876(number abo)188.4 679.8 R 1.176 -.15(ve a)-.15 H .876(bout 10, since).15
+F F2(sendmail)3.376 E F1 .876(will break up a deli)3.376 F -.15(ve)-.25 G .875
+(ry into smaller).15 F .886(batches as needed.)188.4 691.8 R 3.386(Ah)5.886 G
+.887(igher number may reduce load on your system, ho)285.804 691.8 R(w-)-.25 E
+-2.15 -.25(ev e)188.4 703.8 T -.55(r.).25 G EP
+%%Page: 50 45
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-50 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(MAXA)102 96 Q
+-.18(TO)-1.11 G 2.559(M[).18 G 8.26(100] The)159.369 96 R .059
+(maximum number of atoms \(tok)2.559 F .058(ens\) in a single address.)-.1 F
+-.15(Fo)5.058 G 2.558(re).15 G .058(xample, the)457.282 96 R
+(address \231eric@CS.Berk)188.4 108 Q(ele)-.1 E -.65(y.)-.15 G(EDU\232 is se)
+.65 E -.15(ve)-.25 G 2.5(na).15 G(toms.)367.93 108 Q .112(MAXMAILERS [25])102
+124.2 R .112(The maximum number of mailers that may be de\214ned in the con\
+\214guration \214le.).02 F(MAXR)102 140.4 Q(WSETS [100])-.55 E
+(The maximum number of re).01 E(writing sets that may be de\214ned.)-.25 E
+(MAXPRIORITIES [25])102 156.6 Q 2.482(The maximum number of v)188.4 168.6 R
+2.482(alues for the \231Precedence:\232 \214eld that may be)-.25 F
+(de\214ned \(using the)188.4 180.6 Q F0(P)2.5 E F1(line in sendmail.cf\).)2.5 E
+(MAXUSERENVIR)102 196.8 Q(ON [40])-.4 E .399
+(The maximum number of items in the user en)188.4 208.8 R .4
+(vironment that will be passed to)-.4 F(subordinate mailers.)188.4 220.8 Q -.1
+(QU)102 237 S(EUESIZE [1000]).1 E
+(The maximum number of entries that will be processed in a single queue run.)
+2.35 E(MAXMXHOSTS [20])102 253.2 Q
+(The maximum number of MX records we will accept for an)188.4 265.2 Q 2.5(ys)
+-.15 G(ingle host.)439.03 265.2 Q 2.851(An)102 281.4 S .351
+(umber of other compilation options e)117.071 281.4 R 2.851(xist. These)-.15 F
+.35(specify whether or not speci\214c code should be)2.851 F(compiled in.)102
+293.4 Q(DEB)102 309.6 Q 49.56(UG If)-.1 F 1.226(set, deb)3.726 F 1.226
+(ugging information is compiled in.)-.2 F 2.827 -.8(To a)6.226 H 1.227
+(ctually get the deb).8 F(ugging)-.2 E .4(output, the)188.4 321.6 R F0<ad64>2.9
+E F1 .4(\215ag must be used.)2.9 F F0 .4(WE STR)5.4 F(ONGL)-.3 E 2.9(YR)-.92 G
+.4(ECOMMEND THA)412.05 321.6 R(T)-.95 E .97(THIS BE LEFT ON.)188.4 333.6 R F1
+.97(Some people, belie)5.97 F .97(ving that it w)-.25 F .97
+(as a security hole \(it)-.1 F -.1(wa)188.4 345.6 S(s, once\) ha).1 E .3 -.15
+(ve t)-.2 H(urned it of).15 E 2.5(fa)-.25 G(nd thus crippled deb)309.05 345.6 Q
+(uggers.)-.2 E 41.69(NETINET If)102 361.8 R .829
+(set, support for Internet protocol netw)3.33 F .829(orking is compiled in.)-.1
+F(Pre)5.829 E .829(vious v)-.25 F(er)-.15 E(-)-.2 E .177(sions of)188.4 373.8 R
+/F2 10/Times-Italic@0 SF(sendmail)2.677 E F1 .177(referred to this as)2.677 F
+/F3 9/Times-Roman@0 SF -.36(DA)2.678 G(EMON).36 E F1 2.678(;t)C .178
+(his old usage is no)381.71 373.8 R 2.678(wi)-.25 G(ncorrect.)468.74 373.8 Q
+48.35(NETISO If)102 390 R .143(set, support for ISO protocol netw)2.643 F .142
+(orking is compiled in \(it may be appropri-)-.1 F
+(ate to #de\214ne this in the Mak)188.4 402 Q(e\214le instead of conf.h\).)-.1
+E 63.35(LOG If)102 418.2 R .5(set, the)3 F F2(syslo)3 E(g)-.1 E F1 .5
+(routine in use at some sites is used.)3 F .5(This mak)5.5 F .5(es an informa-)
+-.1 F .504(tional log record for each message processed, and mak)188.4 430.2 R
+.504(es a higher priority log)-.1 F(record for internal system errors.)188.4
+442.2 Q(MA)102 458.4 Q 16.12(TCHGECOS Compile)-1.11 F 3.555
+(in the code to do `)6.055 F 3.555(`fuzzy matching')-.74 F 6.055('o)-.74 G
+6.055(nt)404.22 458.4 S 3.555(he GECOS \214eld in)418.055 458.4 R 2.5
+(/etc/passwd. This)188.4 470.4 R(also requires that option G be turned on.)2.5
+E -.35(NA)102 486.6 S 18.15(MED_BIND Compile).35 F .413
+(in code to use the Berk)2.913 F(ele)-.1 E 2.912(yI)-.15 G .412
+(nternet Name Domain \(BIND\) serv)342.41 486.6 R .412(er to)-.15 F(resolv)
+188.4 498.6 Q 2.5(eT)-.15 G(CP/IP host names.)225.74 498.6 Q(NO)102 514.8 Q
+38.76(TUNIX If)-.4 F .247
+(you are using a non-UNIX mail format, you can set this \215ag to turn of)2.747
+F 2.748(fs)-.25 G(pe-)491.23 514.8 Q
+(cial processing of UNIX-style \231From \232 lines.)188.4 526.8 Q -.1(QU)102
+543 S 50.12(EUE This).1 F 1.559
+(\215ag should be set to compile in the queueing code.)4.06 F 1.559
+(If this is not set,)6.559 F
+(mailers must accept the mail immediately or it will be returned to the sender)
+188.4 555 Q(.)-.55 E(SETPR)102 571.2 Q 12.63(OCTITLE If)-.4 F(de\214ned,)3.88 E
+F2(sendmail)3.88 E F1 1.381(will change its)3.881 F F2(ar)3.881 E(gv)-.37 E F1
+1.381(array to indicate its current status.)3.881 F .207
+(This can be used in conjunction with the)188.4 583.2 R F2(ps)2.707 E F1 .206
+(command to \214nd out just what it')2.707 F(s)-.55 E(up to.)188.4 595.2 Q
+57.78(SMTP If)102 611.4 R .756(set, the code to handle user and serv)3.256 F
+.756(er SMTP will be compiled in.)-.15 F .756(This is)5.756 F 2.507
+(only necessary if your machine has some mailer that speaks SMTP \(this)188.4
+623.4 R(means most machines e)188.4 635.4 Q -.15(ve)-.25 G(rywhere\).).15 E
+(UGL)102 651.6 Q 30.46(YUUCP If)-1 F 1.023(you ha)3.523 F 1.323 -.15(ve a U)-.2
+H 1.024(UCP host adjacent to you which is not running a reasonable).15 F -.15
+(ve)188.4 663.6 S .112(rsion of).15 F F2(rmail)2.612 E F1 2.612(,y)C .112
+(ou will ha)263.026 663.6 R .412 -.15(ve t)-.2 H 2.612(os).15 G .112
+(et this \215ag to include the \231remote from sys-)329.234 663.6 R .031
+(name\232 info on the from line.)188.4 675.6 R .032
+(Otherwise, UUCP gets confused about where the)5.032 F(mail came from.)188.4
+687.6 Q 44.45(USERDB Include)102 703.8 R(the)3.449 E F0(experimental)3.449 E F1
+(Berk)3.449 E(ele)-.1 E 3.449(yu)-.15 G .949(ser information database package.)
+341.356 703.8 R(This)5.948 E .27(adds a ne)188.4 715.8 R 2.77(wl)-.25 G -2.15
+-.25(ev e)238.67 715.8 T 2.77(lo).25 G 2.77(fl)262.7 715.8 S .27(ocal name e)
+271.58 715.8 R .27(xpansion between aliasing and forw)-.15 F 2.77(arding. It)
+-.1 F EP
+%%Page: 51 46
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-51)452.9 60 Q/F1 10/Times-Roman@0 SF(also uses the NEWDB package.)188.4
+96 Q(This may change in future releases.)5 E(IDENTPR)102 112.2 Q -1.88 -.4
+(OT O)-.4 H .376(Compile in the IDENT protocol as de\214ned in RFC 1413.)188.4
+112.2 R .375(This def)5.375 F .375(aults on for)-.1 F 1.053(all systems e)188.4
+124.2 R 1.053
+(xcept Ultrix, which apparently has the interesting \231feature\232 that)-.15 F
+.83(when it recei)188.4 136.2 R -.15(ve)-.25 G 3.33(sa\231).15 G .83
+(host unreachable\232 message it closes all open connections)270.18 136.2 R
+1.921(to that host.)188.4 148.2 R 1.921(Since some \214re)6.921 F -.1(wa)-.25 G
+1.922(ll g).1 F(ate)-.05 E -.1(wa)-.25 G 1.922
+(ys send this error code when you).1 F 2.055
+(access an unauthorized port \(such as 113, used by IDENT\), Ultrix cannot)
+188.4 160.2 R(recei)188.4 172.2 Q .3 -.15(ve e)-.25 H(mail from such hosts.).15
+E F0 2.5(6.3. Con\214guration)87 196.2 R(in sr)2.5 E(c/conf)-.18 E(.c)-.15 E F1
+(The follo)127 212.4 Q(wing changes can be made in conf.c.)-.25 E F0 2.5
+(6.3.1. Built-in)102 236.4 R(Header Semantics)2.5 E F1 1.248
+(Not all header semantics are de\214ned in the con\214guration \214le.)142
+252.6 R 1.248(Header lines that should)6.248 F .305(only be included by certai\
+n mailers \(as well as other more obscure semantics\) must be speci\214ed)117
+264.6 R .046(in the)117 276.6 R/F2 10/Times-Italic@0 SF(HdrInfo)2.546 E F1 .046
+(table in)2.546 F F2(conf)2.546 E(.c)-.15 E F1 5.046(.T)C .047
+(his table contains the header name \(which should be in all lo)246.836 276.6 R
+(wer)-.25 E(case\) and a set of header control \215ags \(described belo)117
+288.6 Q(w\), The \215ags are:)-.25 E(H_A)117 304.8 Q 30.97(CHECK Normally)-.4 F
+.007(when the check is made to see if a header line is compatible with)2.508 F
+2.94(am)203.4 316.8 S(ailer)218.56 316.8 Q(,)-.4 E F2(sendmail)2.94 E F1 .441
+(will not delete an e)2.94 F .441(xisting line.)-.15 F .441
+(If this \215ag is set,)5.441 F F2(send-)2.941 E(mail)203.4 328.8 Q F1 .152
+(will delete e)2.652 F -.15(ve)-.25 G 2.652(ne).15 G .152
+(xisting header lines.)293.998 328.8 R .152
+(That is, if this bit is set and the)5.152 F 1.425(mailer does not ha)203.4
+340.8 R 1.725 -.15(ve \215)-.2 H 1.425
+(ag bits set that intersect with the required mailer).15 F 2.204
+(\215ags in the header de\214nition in sendmail.cf, the header line is)203.4
+352.8 R F2(always)4.703 E F1(deleted.)203.4 364.8 Q 51.13(H_EOH If)117 381 R
+.206(this header \214eld is set, treat it lik)2.705 F 2.706(eab)-.1 G .206
+(lank line, i.e., it will signal the end)363.948 381 R
+(of the header and the be)203.4 393 Q(ginning of the message te)-.15 E(xt.)-.15
+E 39.45(H_FORCE Add)117 409.2 R 2.039(this header entry e)4.539 F -.15(ve)-.25
+G 4.539(ni).15 G 4.539(fo)326.225 409.2 S 2.038(ne e)339.094 409.2 R 2.038
+(xisted in the message before.)-.15 F 2.038(If a)7.038 F 2.188
+(header entry does not ha)203.4 421.2 R 2.488 -.15(ve t)-.2 H 2.188
+(his bit set,).15 F F2(sendmail)4.688 E F1 2.189(will not add another)4.689 F
+.62(header line if a header line of this name already e)203.4 433.2 R 3.12
+(xisted. This)-.15 F -.1(wo)3.12 G .62(uld nor).1 F(-)-.2 E
+(mally be used to stamp the message by e)203.4 445.2 Q -.15(ve)-.25 G
+(ryone who handled it.).15 E(H_TRA)117 461.4 Q 39.3(CE If)-.4 F 1.043
+(set, this is a timestamp \(trace\) \214eld.)3.543 F 1.044
+(If the number of trace \214elds in a)6.043 F .706(message e)203.4 473.4 R .705
+(xceeds a preset amount the message is returned on the assump-)-.15 F
+(tion that it has an aliasing loop.)203.4 485.4 Q 46.67(H_RCPT If)117 501.6 R
+.332(set, this \214eld contains recipient addresses.)2.832 F .332
+(This is used by the)5.332 F F0<ad74>2.832 E F1 .333(\215ag to)2.833 F 1.349
+(determine who to send to when it is collecting recipients from the mes-)203.4
+513.6 R(sage.)203.4 525.6 Q(H_FR)117 541.8 Q 43.74(OM This)-.4 F 1.673
+(\215ag indicates that this \214eld speci\214es a sender)4.173 F 6.674(.T)-.55
+G 1.674(he order of these)432.058 541.8 R .898(\214elds in the)203.4 553.8 R F2
+(HdrInfo)3.398 E F1 .898(table speci\214es)3.398 F F2(sendmail)3.398 E F1 1.998
+-.55('s p)D .898(reference for which \214eld).55 F
+(to return error messages to.)203.4 565.8 Q(Let')117 582 Q 2.5(sl)-.55 G
+(ook at a sample)142.28 582 Q F2(HdrInfo)2.5 E F1(speci\214cation:)2.5 E EP
+%%Page: 52 47
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-52 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(struct hdrinfo)
+157 96 Q(HdrInfo[] =)258.19 96 Q({)157 108 Q
+(/* originator \214elds, most to least signi\214cant)189.5 120 Q(*/)5 E 14.72
+("resent-sender", H_FR)177 132 R(OM,)-.4 E 21.38("resent-from", H_FR)177 144 R
+(OM,)-.4 E 41.93("sender", H_FR)177 156 R(OM,)-.4 E 48.59("from", H_FR)177 168
+R(OM,)-.4 E 29.15("full-name", H_A)177 180 R(CHECK,)-.4 E
+(/* destination \214elds */)189.5 192 Q 60.25("to", H_RCPT)177 204 R(,)-.74 E
+33.04("resent-to", H_RCPT)177 216 R(,)-.74 E 59.15("cc", H_RCPT)177 228 R(,)
+-.74 E(/* message identi\214cation and control */)189.5 240 Q 34.15
+("message", H_EOH,)177 252 R("te)177 264 Q 53.18(xt", H_EOH,)-.15 F
+(/* trace \214elds */)189.5 276 Q("recei)177 288 Q -.15(ve)-.25 G 34.56
+(d", H_TRA).15 F(CE|H_FORCE,)-.4 E 49.53(NULL, 0,)177 312 R(};)157 324 Q 2.435
+(This structure indicates that the \231T)117 340.2 R 2.435
+(o:\232, \231Resent-T)-.8 F 2.435
+(o:\232, and \231Cc:\232 \214elds all specify recipient)-.8 F 3.162
+(addresses. An)117 352.2 R 3.162<7999>-.15 G .661(Full-Name:\232 \214eld will \
+be deleted unless the required mailer \215ag \(indicated in)188.154 352.2 R
+.245(the con\214guration \214le\) is speci\214ed.)117 364.2 R .245
+(The \231Message:\232 and \231T)5.245 F -.15(ex)-.7 G .246
+(t:\232 \214elds will terminate the header;).15 F 1.936
+(these are used by random dissenters around the netw)117 376.2 R 1.936(ork w)
+-.1 F 4.436(orld. The)-.1 F(\231Recei)4.436 E -.15(ve)-.25 G 1.936
+(d:\232 \214eld will).15 F(al)117 388.2 Q -.1(wa)-.1 G
+(ys be added, and can be used to trace messages.).1 E .445
+(There are a number of important points here.)142 404.4 R .446
+(First, header \214elds are not added automati-)5.446 F .657
+(cally just because the)117 416.4 R 3.157(ya)-.15 G .657(re in the)216.678
+416.4 R/F2 10/Times-Italic@0 SF(HdrInfo)3.157 E F1 .657(structure; the)3.157 F
+3.157(ym)-.15 G .656(ust be speci\214ed in the con\214guration)358.23 416.4 R
+.727(\214le in order to be added to the message.)117 428.4 R(An)5.728 E 3.228
+(yh)-.15 G .728(eader \214elds mentioned in the con\214guration \214le)312.982
+428.4 R -.2(bu)117 440.4 S 3.24(tn).2 G .74(ot mentioned in the)137.82 440.4 R
+F2(HdrInfo)3.24 E F1 .74(structure ha)3.24 F 1.04 -.15(ve d)-.2 H(ef).15 E .74
+(ault processing performed; that is, the)-.1 F 3.24(ya)-.15 G(re)496.23 440.4 Q
+1.374(added unless the)117 452.4 R 3.874(yw)-.15 G 1.374
+(ere in the message already)201.792 452.4 R 6.375(.S)-.65 G 1.375(econd, the)
+326.595 452.4 R F2(HdrInfo)3.875 E F1 1.375(structure only speci\214es)3.875 F
+.324
+(cliched processing; certain headers are processed specially by ad hoc code re)
+117 464.4 R -.05(ga)-.15 G .324(rdless of the sta-).05 F .48
+(tus speci\214ed in)117 476.4 R F2(HdrInfo)2.98 E F1 5.48(.F)C .481(or e)226.55
+476.4 R .481(xample, the \231Sender:\232 and \231From:\232 \214elds are al)-.15
+F -.1(wa)-.1 G .481(ys scanned on).1 F(ARP)117 490.4 Q .75
+(ANET mail to determine the sender)-.92 F/F3 7/Times-Roman@0 SF(19)282.31 486.4
+Q F1 3.251(;t)289.31 490.4 S .751
+(his is used to perform the \231return to sender\232 func-)298.121 490.4 R
+2.977(tion. The)117 502.4 R .476(\231From:\232 and \231Full-Name:\232 \214elds\
+ are used to determine the full name of the sender if)2.977 F
+(possible; this is stored in the macro)117 514.4 Q F0($x)2.5 E F1
+(and used in a number of w)2.5 E(ays.)-.1 E F0 2.5(6.3.2. Restricting)102 538.4
+R(Use of Email)2.5 E F1 .149
+(If it is necessary to restrict mail through a relay)142 554.6 R 2.649(,t)-.65
+G(he)339.75 554.6 Q F2 -.15(ch)2.65 G(ec).15 E(kcompat)-.2 E F1 .15
+(routine can be modi\214ed.)2.65 F .163(This routine is called for e)117 566.6
+R -.15(ve)-.25 G .163(ry recipient address.).15 F .163(It returns an e)5.163 F
+.163(xit status indicating the status of)-.15 F .895(the message.)117 578.6 R
+.895(The status)5.895 F/F4 9/Times-Roman@0 SF(EX_OK)3.395 E F1 .895
+(accepts the address,)3.395 F F4(EX_TEMPF)3.395 E(AIL)-.666 E F1 .895
+(queues the message for a)3.395 F .264(later try)117 590.6 R 2.764(,a)-.65 G
+.264(nd other v)157.698 590.6 R .264(alues \(commonly)-.25 F F4(EX_UN)2.764 E
+-1.215(AVA)-.315 G(ILABLE)1.215 E F1 2.764(\)r)C .264(eject the message.)
+358.375 590.6 R .263(It is up to)5.264 F F2 -.15(ch)2.763 G(ec).15 E(k-)-.2 E
+(compat)117 602.6 Q F1 .429(to print an error message \(using)2.929 F F2(usr)
+2.929 E(err)-.37 E F1 2.929(\)i)C 2.929(ft)315.032 602.6 S .43
+(he message is rejected.)324.071 602.6 R -.15(Fo)5.43 G 2.93(re).15 G(xample,)
+443.39 602.6 Q F2 -.15(ch)2.93 G(ec).15 E(k-)-.2 E(compat)117 614.6 Q F1
+(could read:)2.5 E .32 LW 76 669.2 72 669.2 DL 80 669.2 76 669.2 DL 84 669.2 80
+669.2 DL 88 669.2 84 669.2 DL 92 669.2 88 669.2 DL 96 669.2 92 669.2 DL 100
+669.2 96 669.2 DL 104 669.2 100 669.2 DL 108 669.2 104 669.2 DL 112 669.2 108
+669.2 DL 116 669.2 112 669.2 DL 120 669.2 116 669.2 DL 124 669.2 120 669.2 DL
+128 669.2 124 669.2 DL 132 669.2 128 669.2 DL 136 669.2 132 669.2 DL 140 669.2
+136 669.2 DL 144 669.2 140 669.2 DL 148 669.2 144 669.2 DL 152 669.2 148 669.2
+DL 156 669.2 152 669.2 DL 160 669.2 156 669.2 DL 164 669.2 160 669.2 DL 168
+669.2 164 669.2 DL 172 669.2 168 669.2 DL 176 669.2 172 669.2 DL 180 669.2 176
+669.2 DL 184 669.2 180 669.2 DL 188 669.2 184 669.2 DL 192 669.2 188 669.2 DL
+196 669.2 192 669.2 DL 200 669.2 196 669.2 DL 204 669.2 200 669.2 DL 208 669.2
+204 669.2 DL 212 669.2 208 669.2 DL 216 669.2 212 669.2 DL/F5 5/Times-Roman@0
+SF(19)93.6 679.6 Q/F6 8/Times-Roman@0 SF(Actually)3.2 I 2.632(,t)-.52 G .632
+(his is no longer true in SMTP; this information is contained in the en)132.488
+682.8 R -.12(ve)-.32 G 2.631(lope. The).12 F .631(older ARP)2.631 F .631
+(ANET protocols did)-.736 F(not completely distinguish en)72 692.4 Q -.12(ve)
+-.32 G(lope from header).12 E(.)-.44 E EP
+%%Page: 53 48
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-53)452.9 60 Q/F1 9/Times-Roman@0 SF(int)157 94.8 Q
+(checkcompat\(to, e\))157 105.6 Q(re)175 116.4 Q(gister ADDRESS *to;)-.135 E
+(re)175 127.2 Q(gister ENVELOPE *e;)-.135 E({)157 138 Q(re)175 148.8 Q
+(gister ST)-.135 E(AB *s;)-.837 E 2.25(s=s)175 170.4 S(tab\("pri)191.578 170.4
+Q -.225(va)-.225 G(te", ST_MAILER, ST_FIND\);).225 E
+(if \(s != NULL && e\255>e_from.q_mailer != LocalMailer &&)175 181.2 Q
+(to->q_mailer == s->s_mailer\))184 192 Q({)175 202.8 Q(usrerr\("No pri)193
+213.6 Q -.225(va)-.225 G(te net mail allo).225 E(wed through this machine"\);)
+-.225 E(return \(EX_UN)193 224.4 Q -1.215(AVA)-.315 G(ILABLE\);)1.215 E(})175
+235.2 Q(if \(MsgSize > 50000 && to\255>q_mailer != LocalMailer\))175 246 Q({)
+175 256.8 Q(usrerr\("Message too lar)193 267.6 Q(ge for non-local deli)-.162 E
+-.135(ve)-.225 G(ry"\);).135 E(NoReturn = TR)193 278.4 Q(UE;)-.36 E
+(return \(EX_UN)193 289.2 Q -1.215(AVA)-.315 G(ILABLE\);)1.215 E(})175 300 Q
+(return \(EX_OK\);)175 310.8 Q(})157 321.6 Q/F2 10/Times-Roman@0 SF .205
+(This w)117 337.8 R .205
+(ould reject messages greater than 50000 bytes unless the)-.1 F 2.705(yw)-.15 G
+.205(ere local.)387.09 337.8 R(The)5.205 E/F3 10/Times-Italic@0 SF(NoReturn)
+2.705 E F2(\215ag)2.705 E 1.196(can be sent to suppress the return of the actu\
+al body of the message in the error return.)117 349.8 R(The)6.197 E(actual use\
+ of this routine is highly dependent on the implementation, and use should be \
+limited.)117 361.8 Q F0 2.5(6.3.3. Load)102 385.8 R -.6 -1(Av e)2.5 H
+(rage Computation)1 E F2 .18(The routine)142 402 R F3 -.1(ge)2.68 G(tla).1 E F2
+.18(should return an approximation of the current system load a)2.68 F -.15(ve)
+-.2 G .18(rage as an).15 F(inte)117 414 Q(ger)-.15 E 5(.T)-.55 G
+(here are four v)157.68 414 Q
+(ersions included on compilation \215ags as described abo)-.15 E -.15(ve)-.15 G
+(.).15 E F0 2.5(6.3.4. New)102 438 R(Database Map Classes)2.5 E F2(Ne)142 454.2
+Q 2.875(wk)-.25 G .675 -.15(ey m)168.405 454.2 T .375(aps can be added by crea\
+ting a class initialization function and a lookup func-).15 F 2.5(tion. These)
+117 466.2 R(are then added to the routine)2.5 E F3(setupmaps.)2.5 E F2
+(The initialization function is called as)142 482.4 Q F3(xxx)157 498.6 Q F2
+(_map_init\(MAP *map, char *mapname, char *ar)A(gs\))-.18 E(The)117 514.8 Q F3
+(map)2.555 E F2 .055(is an internal data structure.)2.555 F(The)5.055 E F3
+(mapname)2.555 E F2 .054(is the name of the map \(used for error mes-)2.554 F
+2.819(sages\). The)117 526.8 R F3(ar)2.819 E(gs)-.37 E F2 .32(is a pointer to \
+the rest of the con\214guration \214le line; \215ags and \214lenames can be)
+2.819 F -.15(ex)117 538.8 S .675(tracted from this line.).15 F .675
+(The initialization function must return)5.675 F F1(TR)3.175 E(UE)-.36 E F2
+.674(if it successfully opened)3.174 F(the map,)117 550.8 Q F1 -.666(FA)2.5 G
+(LSE).666 E F2(otherwise.)2.5 E(The lookup function is called as)142 567 Q F3
+(xxx)157 583.2 Q F2(_map_lookup\(MAP *map, char b)A(uf[], int b)-.2 E
+(ufsize, char **a)-.2 E 1.3 -.65(v, i)-.2 H(nt *statp\)).65 E(The)117 599.4 Q
+F3(map)3.475 E F2 .975(de\214nes the map internally)3.475 F 5.975(.T)-.65 G
+.975(he parameters)277.18 599.4 R F3 -.2(bu)3.475 G(f).2 E F2(and)3.475 E F3
+-.2(bu)3.475 G(fsize).2 E F2(ha)3.476 E 1.276 -.15(ve t)-.2 H .976(he input k)
+.15 F -.15(ey)-.1 G 5.976(.T)-.5 G(his)492.33 599.4 Q .043
+(may be \(and often is\) used destructi)117 611.4 R -.15(ve)-.25 G(ly).15 E
+5.043(.T)-.65 G(he)289.831 611.4 Q F3(av)2.543 E F2 .043(is a list of ar)2.543
+F .042(guments passed in from the re)-.18 F(write)-.25 E 3.654(line. The)117
+623.4 R 1.154(lookup function should return a pointer to the ne)3.654 F 3.655
+(wv)-.25 G 3.655(alue. IF)378.335 623.4 R 1.155(the map lookup f)3.655 F(ails,)
+-.1 E F3(*statp)117 635.4 Q F2 1.272(should be set to an e)3.772 F 1.272
+(xit status code; in particular)-.15 F 3.772(,i)-.4 G 3.771(ts)357.652 635.4 S
+1.271(hould be set to)368.093 635.4 R F1(EX_TEMPF)3.771 E(AIL)-.666 E F2(if)
+3.771 E(reco)117 647.4 Q -.15(ve)-.15 G(ry is to be attempted by the higher le)
+.15 E -.15(ve)-.25 G 2.5(lc).15 G(ode.)308.76 647.4 Q F0 2.5(6.3.5. Queueing)
+102 671.4 R(Function)2.5 E F2 .782(The routine)142 687.6 R F3(shouldqueue)3.282
+E F2 .783(is called to decide if a message should be queued or processed)3.283
+F(immediately)117 699.6 Q 6.619(.T)-.65 G 1.618
+(ypically this compares the message priority to the current load a)180.779
+699.6 R -.15(ve)-.2 G 4.118(rage. The).15 F(def)117 711.6 Q
+(ault de\214nition is:)-.1 E EP
+%%Page: 54 49
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-54 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF(bool)157 96 Q
+(shouldqueue\(pri, ctime\))157 108 Q(long pri;)175 120 Q(time_t ctime;)175 132
+Q({)157 144 Q(if \(CurrentLA < QueueLA\))175 156 Q(return \(F)193 168 Q
+(ALSE\);)-.74 E(if \(CurrentLA >= RefuseLA\))175 180 Q(return \(TR)193 192 Q
+(UE\);)-.4 E(return \(pri > \(QueueF)175 204 Q
+(actor / \(CurrentLA \255 QueueLA + 1\)\)\);)-.15 E(})157 216 Q 2.062
+(If the current load a)117 232.2 R -.15(ve)-.2 G 2.062(rage \(global v).15 F
+(ariable)-.25 E/F2 10/Times-Italic@0 SF(Curr)4.562 E(entLA)-.37 E F1 4.562(,w)C
+2.062(hich is set before this function is)361.636 232.2 R 1.058
+(called\) is less than the lo)117 244.2 R 3.558(wt)-.25 G 1.058
+(hreshold load a)234.198 244.2 R -.15(ve)-.2 G 1.058(rage \(option).15 F F0(x)
+3.557 E F1 3.557(,v)C(ariable)375.526 244.2 Q F2(QueueLA)3.557 E F1(\),)A F2
+(shouldqueue)3.557 E F1(returns)117 256.2 Q/F3 9/Times-Roman@0 SF -.666(FA)
+2.586 G(LSE).666 E F1 .086(immediately \(that is, it should)2.586 F F2(not)
+2.586 E F1 2.586(queue\). If)2.586 F .086(the current load a)2.586 F -.15(ve)
+-.2 G .087(rage e).15 F .087(xceeds the)-.15 F .588(high threshold load a)117
+268.2 R -.15(ve)-.2 G .588(rage \(option).15 F F0(X)3.087 E F1 3.087(,v)C
+(ariable)281.846 268.2 Q F2(RefuseLA)3.087 E F1(\),)A F2(shouldqueue)3.087 E F1
+(returns)3.087 E F3(TR)3.087 E(UE)-.36 E F1(immedi-)3.087 E(ately)117 280.2 Q
+7.125(.O)-.65 G 2.125
+(therwise, it computes the function based on the message priority)152.635 280.2
+R 4.626(,t)-.65 G 2.126(he queue f)438.208 280.2 R(actor)-.1 E(\(option)117
+292.2 Q F0(q)2.5 E F1 2.5(,g)C(lobal v)163.95 292.2 Q(ariable)-.25 E F2(QueueF)
+2.5 E(actor)-.75 E F1(\), and the current and threshold load a)A -.15(ve)-.2 G
+(rages.).15 E 1.067(An implementation wishing to tak)142 308.4 R 3.567(et)-.1 G
+1.066(he actual age of the message into account can also)293.625 308.4 R 1.41
+(use the)117 320.4 R F2(ctime)3.91 E F1(parameter)3.91 E 3.91(,w)-.4 G 1.41
+(hich is the time that the message w)229.15 320.4 R 1.41
+(as \214rst submitted to)-.1 F F2(sendmail)3.91 E F1(.)A .929(Note that the)117
+332.4 R F2(pri)3.428 E F1 .928
+(parameter is already weighted by the number of times the message has been)
+3.428 F .395(tried \(although this tends to lo)117 344.4 R .395
+(wer the priority of the message with time\); the e)-.25 F .395
+(xpectation is that)-.15 F(the)117 356.4 Q F2(ctime)2.674 E F1 -.1(wo)2.674 G
+.174(uld be used as an \231escape clause\232 to ensure that messages are e).1 F
+-.15(ve)-.25 G .174(ntually processed.).15 F F0 2.5(6.3.6. Refusing)102 380.4 R
+(Incoming SMTP Connections)2.5 E F1 1.148(The function)142 396.6 R F2 -.37(re)
+3.648 G(fuseconnections).37 E F1(returns)3.648 E F3(TR)3.648 E(UE)-.36 E F1
+1.148(if incoming SMTP connections should be)3.648 F 3.564(refused. The)117
+408.6 R 1.063(current implementation is based e)3.563 F(xclusi)-.15 E -.15(ve)
+-.25 G 1.063(ly on the current load a).15 F -.15(ve)-.2 G 1.063(rage and the)
+.15 F(refuse load a)117 420.6 Q -.15(ve)-.2 G(rage option \(option).15 E F0(X)
+2.5 E F1 2.5(,g)C(lobal v)273.56 420.6 Q(ariable)-.25 E F2(RefuseLA)2.5 E F1
+(\):)A(bool)157 436.8 Q(refuseconnections\(\))157 448.8 Q({)157 460.8 Q
+(return \(CurrentLA >= RefuseLA\);)175 472.8 Q(})157 484.8 Q 2.5(Am)117 501 S
+(ore cle)134.5 501 Q -.15(ve)-.25 G 2.5(ri).15 G
+(mplementation could look at more system resources.)179.08 501 Q F0 2.5
+(6.3.7. Load)102 525 R -.6 -1(Av e)2.5 H(rage Computation)1 E F1 .243
+(The routine)142 541.2 R F2 -.1(ge)2.743 G(tla).1 E F1 .243
+(returns the current load a)2.743 F -.15(ve)-.2 G .243
+(rage \(as a rounded inte).15 F 2.743(ger\). The)-.15 F(distrib)2.744 E(ution)
+-.2 E(includes se)117 553.2 Q -.15(ve)-.25 G(ral possible implementations.).15
+E F0 2.5(6.4. Con\214guration)87 577.2 R(in sr)2.5 E(c/daemon.c)-.18 E F1 .4
+(The \214le)127 593.4 R F2(sr)2.9 E(c/daemon.c)-.37 E F1 .4
+(contains a number of routines that are dependent on the local netw)2.9 F(ork-)
+-.1 E(ing en)102 605.4 Q 2.5(vironment. The)-.4 F -.15(ve)2.5 G
+(rsion supplied assumes you ha).15 E .3 -.15(ve B)-.2 H(SD style sock).15 E
+(ets.)-.1 E 2.16(In pre)127 621.6 R 2.16
+(vious releases, we recommended that you modify the routine)-.25 F F2
+(maphostname)4.66 E F1 2.16(if you)4.66 F -.1(wa)102 633.6 S 1.919
+(nted to generalize).1 F F0($[)4.418 E F1(...)4.418 E F0($])4.418 E F1 4.418
+(lookups. W)4.418 F 4.418(en)-.8 G 2.418 -.25(ow r)293.906 633.6 T 1.918
+(ecommend that you create a ne).25 F 4.418(wk)-.25 G -.15(ey)463.632 633.6 S
+1.918(ed map).15 F(instead.)102 645.6 Q F0 2.5(7. CHANGES)72 669.6 R
+(IN VERSION 8)2.5 E F1 .172(The follo)112 685.8 R .172
+(wing summarizes changes since the last commonly a)-.25 F -.25(va)-.2 G .173
+(ilable v).25 F .173(ersion of)-.15 F F2(sendmail)2.673 E F1(\(5.67\):)2.673 E
+EP
+%%Page: 55 50
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-55)452.9 60 Q 2.5(7.1. Connection)87 96 R(Caching)2.5 E/F1 10
+/Times-Roman@0 SF .398(Instead of closing SMTP connections immediately)127
+112.2 R 2.897(,t)-.65 G .397(hose connections are cached for possible)339.005
+112.2 R .597(future use.)102 124.2 R .597(The adv)5.597 F .597
+(ent of MX records made this ef)-.15 F(fecti)-.25 E .897 -.15(ve f)-.25 H .598
+(or mailing lists; in addition, substantial).15 F(performance impro)102 136.2 Q
+-.15(ve)-.15 G(ments can be e).15 E(xpected for queue processing.)-.15 E F0 2.5
+(7.2. MX)87 160.2 R(Piggybacking)2.5 E F1 1.258(If tw)127 176.4 R 3.757(oh)-.1
+G 1.257(osts with dif)161.075 176.4 R 1.257
+(ferent names in a single message happen to ha)-.25 F 1.557 -.15(ve t)-.2 H
+1.257(he same set of MX).15 F .94(hosts, the)102 188.4 R 3.44(yc)-.15 G .94
+(an be sent in the same transaction.)153.45 188.4 R -1.11(Ve)5.94 G .94
+(rsion 8 notices this and tries to batch the mes-)1.11 F(sages.)102 200.4 Q F0
+2.5(7.3. RFC)87 224.4 R(1123 Compliance)2.5 E F1 3.463(An)127 240.6 S .963
+(umber of changes ha)142.683 240.6 R 1.262 -.15(ve b)-.2 H .962
+(een made to mak).15 F(e)-.1 E/F2 10/Times-Italic@0 SF(sendmail)3.462 E F1 .962
+(\231conditionally compliant\232 \(that is,)3.462 F F2(sendmail)102 252.6 Q F1
+.049(satis\214es all of the \231MUST\232 clauses and most b)2.549 F .05
+(ut not all of the \231SHOULD\232 clauses in RFC)-.2 F(1123\).)102 264.6 Q
+(The major areas of change are \(numbers are RFC 1123 section numbers\):)127
+280.8 Q 15(5.2.7 Response)102 297 R(to RCPT command is f)2.5 E(ast.)-.1 E 15
+(5.2.8 Numeric)102 313.2 R(IP addresses are logged in Recei)2.5 E -.15(ve)-.25
+G(d: lines.).15 E 10(5.2.17 Self)102 329.4 R
+(domain literal is properly handled.)2.5 E 15(5.3.2 Better)102 345.6 R
+(control o)2.5 E -.15(ve)-.15 G 2.5(ri).15 G(ndi)220.02 345.6 Q
+(vidual timeouts.)-.25 E 15(5.3.3 Error)102 361.8 R
+(messages are sent as \231From:<>\232.)2.5 E 15(5.3.3 Error)102 378 R
+(messages are ne)2.5 E -.15(ve)-.25 G 2.5(rs).15 G(ent to \231<>\232.)246.28
+378 Q 15(5.3.3 Route-addrs)102 394.2 R(are pruned.)2.5 E(The areas in which)102
+410.4 Q F2(sendmail)2.5 E F1(is not \231unconditionally compliant\232 are:)2.5
+E(5.2.6)102 426.6 Q F2(Sendmail)139.5 426.6 Q F1(does do header munging.)2.5 E
+(5.2.10)102 442.8 Q F2(Sendmail)139.5 442.8 Q F1(doesn')2.5 E 2.5(ta)-.18 G -.1
+(lwa)215.42 442.8 S(ys use the e).1 E(xact SMTP message te)-.15 E
+(xt as listed in RFC 821.)-.15 E(5.3.1.1)102 459 Q F2(Sendmail)139.5 459 Q F1
+(doesn')2.5 E 2.5(tg)-.18 G
+(uarantee only one connect for each host in queue runs.)215.98 459 Q(5.3.1.1)
+102 475.2 Q F2(Sendmail)139.5 475.2 Q F1(doesn')2.5 E 2.5(ta)-.18 G -.1(lwa)
+215.42 475.2 S(ys pro).1 E(vide adequate concurrenc)-.15 E 2.5(yl)-.15 G
+(imits.)366.54 475.2 Q F0 2.5(7.4. Extended)87 499.2 R(SMTP Support)2.5 E F1
+-1.11(Ve)127 515.4 S .155(rsion 8 includes both sending and recei)1.11 F .154
+(ving support for Extended SMTP support as de\214ned)-.25 F(by RFC 1425 \(basi\
+c\) and RFC 1427 \(SIZE\); and limited support for RFC 1426 \(BOD)102 527.4 Q
+(Y\).)-.55 E F0 2.5(7.5. Eight-Bit)87 551.4 R(Clean)2.5 E F1(Pre)127 567.6 Q
+1.263(vious v)-.25 F 1.263(ersions of)-.15 F F2(sendmail)3.763 E F1 1.264
+(used the 0200 bit for quoting.)3.763 F 1.264(This v)6.264 F 1.264(ersion a)
+-.15 F -.2(vo)-.2 G 1.264(ids that use.).2 F(Ho)102 579.6 Q(we)-.25 E -.15(ve)
+-.25 G .8 -.4(r, f).15 H
+(or compatibility with RFC 822, you can set option `7' to get se).4 E -.15(ve)
+-.25 G 2.5(nb).15 G(it stripping.)418.86 579.6 Q(Indi)127 595.8 Q
+(vidual mailers can still produce se)-.25 E -.15(ve)-.25 G 2.5(nb).15 G
+(it output using the `7' mailer \215ag.)300.77 595.8 Q F0 2.5(7.6. User)87
+619.8 R(Database)2.5 E F1 1.073(The user database is an as-yet e)127 636 R
+1.072(xperimental attempt to pro)-.15 F 1.072(vide uni\214ed lar)-.15 F 1.072
+(ge-site name sup-)-.18 F 2.5(port. W)102 648 R 2.5(ea)-.8 G
+(re installing it at Berk)145.63 648 Q(ele)-.1 E(y; future v)-.15 E
+(ersions may sho)-.15 E 2.5(ws)-.25 G(igni\214cant modi\214cations.)363.57 648
+Q F0 2.5(7.7. Impr)87 672 R -.1(ove)-.18 G 2.5(dB).1 G(IND Support)158.01 672 Q
+F1 .489(The BIND support, particularly for MX records, had a number of anno)127
+688.2 R .49(ying \231features\232 which)-.1 F(ha)102 700.2 Q 1.212 -.15(ve b)
+-.2 H .912(een remo).15 F -.15(ve)-.15 G 3.412(di).15 G 3.412(nt)187.116 700.2
+S .912(his release.)198.308 700.2 R .912(In particular)5.912 F 3.412(,t)-.4 G
+.912(hese more tightly bind \(pun intended\) the name)307.916 700.2 R(serv)102
+712.2 Q(er to)-.15 E F2(sendmail)2.5 E F1 2.5(,s)C 2.5(ot)184.06 712.2 S
+(hat the name serv)194.34 712.2 Q
+(er resolution rules are incorporated directly into)-.15 E F0(sendmail)2.5 E F1
+(.)A EP
+%%Page: 56 51
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-56 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E 2.5(7.8. K)87 96 R(ey)-.25 E(ed Files)
+-.1 E/F1 10/Times-Roman@0 SF .365(Generalized k)127 112.2 R -.15(ey)-.1 G .365
+(ed \214les is an idea tak).15 F .365(en directly from)-.1 F/F2 9/Times-Roman@0
+SF(ID)2.866 E(A)-.36 E/F3 10/Times-Italic@0 SF(sendmail)2.866 E F1 .366
+(\(albeit with a completely)2.866 F(dif)102 124.2 Q(ferent implementation\).)
+-.25 E(The)5 E 2.5(yc)-.15 G(an be useful on lar)239.63 124.2 Q(ge sites.)-.18
+E -1.11(Ve)127 140.4 S(rsion 8 also understands YP)1.11 E(.)-1.11 E F0 2.5
+(7.9. Multi-W)87 164.4 R(ord Classes)-.75 E F1(Classes can no)127 180.6 Q 2.5
+(wb)-.25 G 2.5(em)200.35 180.6 S(ultiple w)215.07 180.6 Q 2.5(ords. F)-.1 F
+(or e)-.15 E(xample,)-.15 E(CShofmann.CS.Berk)142 196.8 Q(ele)-.1 E -.65(y.)
+-.15 G(EDU).65 E(allo)102 213 Q 2.664
+(ws you to match the entire string \231hofmann.CS.Berk)-.25 F(ele)-.1 E -.65
+(y.)-.15 G 2.663(EDU\232 using the single construct).65 F(\231$=S\232.)102 225
+Q F0 2.5(7.10. Deferr)87 249 R(ed Macr)-.18 E 2.5(oE)-.18 G(xpansion)189.94 249
+Q F1(The)127 265.2 Q F0($&)2.5 E F3(x)A F1(construct has been adopted from)2.5
+E F2(ID)2.5 E(A)-.36 E F1(.)A F0 2.5(7.11. IDENT)87 289.2 R(Pr)2.5 E
+(otocol Support)-.18 E F1
+(The IDENT protocol as de\214ned in RFC 1413 is supported.)127 305.4 Q F0 2.5
+(7.12. P)87 329.4 R(arsing Bug Fixes)-.1 E F1 4.03(An)127 345.6 S 1.53
+(umber of small b)143.25 345.6 R 1.53(ugs ha)-.2 F 1.53
+(ving to do with things lik)-.2 F 4.03(eb)-.1 G 1.53
+(ackslash-escaped quotes inside of)364.72 345.6 R(comments ha)102 357.6 Q .3
+-.15(ve b)-.2 H(een \214x).15 E(ed.)-.15 E F0 2.5(7.13. Separate)87 381.6 R(En)
+2.5 E -.1(ve)-.4 G(lope/Header Pr).1 E(ocessing)-.18 E F1 .854
+(Since the From: line is passed in separately from the en)127 397.8 R -.15(ve)
+-.4 G .854(lope sender).15 F 3.354(,t)-.4 G .854(hese ha)420.978 397.8 R 1.154
+-.15(ve b)-.2 H .854(oth been).15 F .427(made visible; the)102 409.8 R F0($g)
+2.927 E F1 .427(macro is set to the en)2.927 F -.15(ve)-.4 G .428
+(lope sender during processing of mailer ar).15 F .428(gument v)-.18 F(ec-)-.15
+E(tors and the header sender during processing of headers.)102 421.8 Q .085
+(It is also possible to specify separate per)127 438 R .085(-mailer en)-.2 F
+-.15(ve)-.4 G .084(lope and header processing.).15 F(The)5.084 E F0(S)2.584 E
+F1(ender)A(-)-.2 E -.55(RW)102 450 S .512(Set and).55 F F0(R)3.012 E F1
+(ecipientR)A .512(Wset ar)-.55 F .512
+(guments for mailers can be speci\214ed as)-.18 F F3(en)3.013 E(velope/header)
+-.4 E F1 .513(to gi)3.013 F .813 -.15(ve d)-.25 H(if-).15 E(ferent re)102 462 Q
+(writings for en)-.25 E -.15(ve)-.4 G(lope v).15 E(ersus header addresses.)-.15
+E F0 2.5(7.14. Owner)87 486 R(-List Pr)-.37 E(opagates to En)-.18 E -.1(ve)-.4
+G(lope).1 E F1 1.001(When an alias has an associated o)127 502.2 R 1
+(wner\255list name, that alias is used to change the en)-.25 F -.15(ve)-.4 G
+(lope).15 E(sender address.)102 514.2 Q(This will cause do)5 E
+(wnstream errors to be returned to that o)-.25 E(wner)-.25 E(.)-.55 E F0 2.5
+(7.15. Dynamic)87 538.2 R(Header Allocation)2.5 E F1(The \214x)127 554.4 Q
+(ed size limit on header lines has been eliminated.)-.15 E F0 2.5(7.16. New)87
+578.4 R(Command Line Flags)2.5 E F1(The)127 594.6 Q F0<ad42>2.5 E F1
+(\215ag has been added to pass in body type information.)2.5 E(The)127 610.8 Q
+F0<ad70>2.5 E F1(\215ag has been added to pass in protocol information.)2.5 E
+(The)127 627 Q F0<ad58>2.6 E F1 .1(\215ag has been added to allo)2.6 F 2.6(wl)
+-.25 G .1(ogging of all protocol in and out of)279.89 627 R F3(sendmail)2.6 E
+F1 .1(for deb)2.6 F(ug-)-.2 E(ging.)102 639 Q F0 2.5(7.17. Enhanced)87 663 R
+(Command Line Flags)2.5 E F1(The)127 679.2 Q F0<ad71>4.007 E F1 1.507(\215ag c\
+an limit limit a queue run to speci\214c recipients, senders, or queue ids usi\
+ng)4.007 F F0(\255qR)102 691.2 Q F3(substring)A F0 2.5<2cad>C(qS)168.41 691.2 Q
+F3(substring)A F0 2.5(,o)C 2.5<72ad>226.76 691.2 S(qI)239.4 691.2 Q F3
+(substring)A F0 -.18(re)2.5 G(specti).18 E -.1(ve)-.1 G(ly).1 E(.)-.7 E EP
+%%Page: 57 52
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-57)452.9 60 Q 2.5(7.18. New)87 96 R(and Old Con\214guration Line T)2.5
+E(ypes)-.74 E/F1 10/Times-Roman@0 SF(The)127 112.2 Q F0(T)2.766 E F1(\(T)2.766
+E .267(rusted users\) con\214guration line has been deleted.)-.35 F .267
+(It will still be accepted b)5.267 F .267(ut will be)-.2 F(ignored.)102 124.2 Q
+(The)127 140.4 Q F0(K)2.5 E F1(line has been added to declare database maps.)
+2.5 E(The)127 156.6 Q F0(V)2.5 E F1
+(line has been added to declare the con\214guration v)2.5 E(ersion le)-.15 E
+-.15(ve)-.25 G(l.).15 E(The)127 172.8 Q F0(M)2.797 E F1 .296(line has a \231D=\
+\232 \214eld that lets you change into a temporary directory while that mailer)
+2.797 F(is running.)102 184.8 Q F0 2.5(7.19. New)87 208.8 R(Options)2.5 E F1
+(Se)127 225 Q -.15(ve)-.25 G .9(ral ne).15 F 3.4(wo)-.25 G .9(ptions ha)184.8
+225 R 1.2 -.15(ve b)-.2 H .9(een added, man).15 F 3.4(yt)-.15 G 3.4(os)314.89
+225 S .9(upport ne)327.18 225 R 3.4(wf)-.25 G .9(eatures, others to allo)379.83
+225 R 3.4(wt)-.25 G(uning)481.22 225 Q 1.187(that w)102 237 R 1.187(as pre)-.1
+F 1.187(viously a)-.25 F -.25(va)-.2 G 1.187(ilable only by recompiling.).25 F
+(The)6.186 E 3.686(ya)-.15 G 1.186(re described in detail in Section 5.1.5.)
+345.514 237 R(Brie\215y)102 249 Q(,)-.65 E 31(bI)102 265.2 S
+(nsist on a minimum number of disk blocks.)141.33 265.2 Q 29.33(CS)102 281.4 S
+(et checkpoint interv)143.56 281.4 Q(al.)-.25 E 29.89(ED)102 297.6 S(ef)145.22
+297.6 Q(ault error message.)-.1 E 28.78(GE)102 313.8 S(nable GECOS matching.)
+144.11 313.8 Q 31(hM)102 330 S(aximum hop count.)146.89 330 Q 33.22(jS)102
+346.2 S(end errors in MIME-encapsulated format.)143.56 346.2 Q 32.11(JF)102
+362.4 S(orw)143.41 362.4 Q(ard \214le path.)-.1 E 31(kC)102 378.6 S
+(onnection cache size)144.67 378.6 Q 28.78(KC)102 394.8 S
+(onnection cache lifetime.)144.67 394.8 Q 33.22(lE)102 411 S .333
+(nable Errors-T)144.11 411 R .333(o: header)-.8 F 5.334(.T)-.55 G .334
+(hese headers violate RFC 1123; this option is included to pro-)252.89 411 R
+(vide back compatibility with old v)138 423 Q(ersions of)-.15 E/F2 10
+/Times-Italic@0 SF(sendmail)2.5 E F1(.)A 28.78(OS)102 439.2 S
+(et incoming SMTP daemon options, such as an alternate SMTP port.)143.56 439.2
+Q 31(pP)102 455.4 S(ri)143.56 455.4 Q -.25(va)-.25 G .3 -.15(cy o).25 H
+(ptions.).15 E 29.33(RD)102 471.6 S(on')145.22 471.6 Q 2.5(tp)-.18 G
+(rune route-addrs.)168.65 471.6 Q 28.78(UU)102 487.8 S(ser database spec.)
+145.22 487.8 Q 28.78(VF)102 504 S(allback \231MX\232 host.)143.41 504 Q 28.78
+<7799>102 520.2 S(Best MX\232 handling technique.)142.44 520.2 Q 31(7D)102
+536.4 S 2.5(on)145.22 536.4 S(ot run eight bit clean.)157.72 536.4 Q F0 2.5
+(7.20. Extended)87 560.4 R(Options)2.5 E F1(The)127 576.6 Q F0(r)3.764 E F1
+1.264(\(read timeout\),)3.764 F F0(I)3.764 E F1 1.264(\(use BIND\), and)3.764 F
+F0(T)3.764 E F1 1.264(\(queue timeout\) options ha)3.764 F 1.564 -.15(ve b)-.2
+H 1.264(een e).15 F 1.264(xtended to)-.15 F(pass in more information.)102 588.6
+Q F0 2.5(7.21. New)87 612.6 R(Mailer Flags)2.5 E F1(Se)127 628.8 Q -.15(ve)-.25
+G(ral ne).15 E 2.5(wm)-.25 G(ailer \215ags ha)185.78 628.8 Q .3 -.15(ve b)-.2 H
+(een added.).15 E 31.56(aT)102 645 S .636
+(ry to use ESMTP when creating a connection.)143.76 645 R .636
+(If this is not set,)5.636 F F2(sendmail)3.136 E F1 .636(will still try if)
+3.136 F .221(the other end hints that it kno)138 657 R .22
+(ws about ESMTP in its greeting message; this \215ag says to try)-.25 F -2.15
+-.25(ev e)138 669 T 2.595(ni).25 G 2.595(fi)161.855 669 S 2.595(td)170.56 669 S
+(oesn')180.935 669 Q 2.595(th)-.18 G 2.595(int. If)212.79 669 R .095
+(the EHLO \(e)2.595 F .095(xtended hello\) command f)-.15 F(ails,)-.1 E F2
+(sendmail)2.596 E F1 -.1(fa)2.596 G .096(lls back to).1 F(old SMTP)138 681 Q(.)
+-1.11 E 31(bE)102 697.2 S
+(nsure that there is a blank line at the end of all messages.)144.11 697.2 Q
+31.56(cS)102 713.4 S .68(trip all comments from addresses; this should only be\
+ used as a last resort when dealing)143.56 713.4 R(with crank)138 725.4 Q 2.5
+(ym)-.15 G(ailers.)195.62 725.4 Q EP
+%%Page: 58 53
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 193.36(SMM:08-58 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 31(gN)102 96 S
+-2.15 -.25(ev e)145.22 96 T 2.64(ru).25 G .14(se the null sender as the en)
+169.67 96 R -.15(ve)-.4 G .141(lope sender).15 F 2.641(,e)-.4 G -.15(ve)341.495
+96 S 2.641(nw).15 G .141(hen running SMTP)365.646 96 R 5.141(.A)-1.11 G .141
+(lthough this)456.349 96 R 1.521(violates RFC 1123, it may be necessary when y\
+ou must deal with some obnoxious old)138 108 R(hosts.)138 120 Q 31(7S)102 136.2
+S(trip all output to 7 bits.)143.56 136.2 Q F0 2.5(7.22. New)87 160.2 R(Pr)2.5
+E(e-De\214ned Macr)-.18 E(os)-.18 E F1(The follo)127 176.4 Q
+(wing macros are pre-de\214ned:)-.25 E 23.5($k The)102 192.6 R
+(UUCP node name, nominally from)2.5 E/F2 10/Times-Italic@0 SF(uname)2.5 E F1
+(\(2\) call.)A 20.72($m The)102 208.8 R(domain part of our full hostname.)2.5 E
+23.5($_ The)102 225 R(RFC 1413-pro)2.5 E(vided sender address.)-.15 E F0 2.5
+(7.23. New)87 249 R(LHS T)2.5 E(ok)-.92 E(en)-.1 E F1 -1.11(Ve)127 265.2 S
+1.375(rsion 8 allo)1.11 F(ws)-.25 E F0($@)3.875 E F1 1.376
+(on the Left Hand Side of an \231R\232 line to match zero tok)3.875 F 3.876
+(ens. This)-.1 F(is)3.876 E(intended to be used to match the null input.)102
+277.2 Q F0 2.5(7.24. Bigger)87 301.2 R(Defaults)2.5 E F1 -1.11(Ve)127 317.4 S
+1.284(rsion 8 allo)1.11 F 1.284(ws up to 100 rulesets instead of 30.)-.25 F
+1.283(It is recommended that rulesets 0\2559 be)6.284 F(reserv)102 329.4 Q
+(ed for)-.15 E F2(sendmail)2.5 E F1 1.1 -.55('s d)D
+(edicated use in future releases.).55 E
+(The total number of MX records that can be used has been raised to 20.)127
+345.6 Q .335(The number of queued messages that can be handled at one time has\
+ been raised from 600 to)127 361.8 R(1000.)102 373.8 Q F0 2.5(7.25. Differ)87
+397.8 R(ent Default T)-.18 E(uning P)-.92 E(arameters)-.1 E F1 -1.11(Ve)127 414
+S .8(rsion 8 has changed the def)1.11 F .8
+(ault parameters for tuning queue costs to mak)-.1 F 3.3(et)-.1 G .8
+(he number of)449.08 414 R .712(recipients more important than the size of the\
+ message \(for small messages\).)102 426 R .712(This is reasonable if)5.712 F
+(you are connected with reasonably f)102 438 Q(ast links.)-.1 E F0 2.5(7.26. A)
+87 462 R(uto-Quoting in Addr)-.5 E(esses)-.18 E F1(Pre)127 478.2 Q(viously)-.25
+E 2.611(,t)-.65 G .111(he \231Full Name <email address>\232 syntax w)176.771
+478.2 R .111(ould generate incorrect protocol output)-.1 F
+(if \231Full Name\232 had special characters such as dot.)102 490.2 Q(This v)5
+E(ersion puts quotes around such names.)-.15 E F0 2.5(7.27. Symbolic)87 514.2 R
+(Names On Err)2.5 E(or Mailer)-.18 E F1(Se)127 530.4 Q -.15(ve)-.25 G
+(ral names ha).15 E .3 -.15(ve b)-.2 H(een b).15 E
+(uilt in to the $@ portion of the $#error mailer)-.2 E(.)-.55 E F0 2.5
+(7.28. SMTP)87 554.4 R(VRFY Doesn't Expand)2.5 E F1(Pre)127 570.6 Q 1.437
+(vious v)-.25 F 1.437(ersions of)-.15 F F2(sendmail)3.937 E F1 1.438
+(treated VRFY and EXPN the same.)3.937 F 1.438(In this v)6.438 F 1.438
+(ersion, VRFY)-.15 F(doesn')102 582.6 Q 2.5(te)-.18 G(xpand aliases or follo)
+138.05 582.6 Q 2.5(w.)-.25 G(forw)235.84 582.6 Q(ard \214les.)-.1 E
+(EXPN still does.)5 E .682(As an optimization, if you run with your def)127
+598.8 R .681(ault deli)-.1 F -.15(ve)-.25 G .681
+(ry mode being queue-only or deli).15 F -.15(ve)-.25 G -.2(r-).15 G 1.582
+(in-background, the RCPT command will also not chase aliases and .forw)102
+610.8 R 1.582(ard \214les.)-.1 F 1.583(It will chase)6.582 F
+(them when it processes the queue.)102 622.8 Q F0 2.5(7.29. [IPC])87 646.8 R
+(Mailers Allo)2.5 E 2.5(wM)-.1 G(ultiple Hosts)210.49 646.8 Q F1 .448
+(When an address resolv)127 663 R .448
+(es to a mailer that has \231[IPC]\232 as its \231P)-.15 F .447
+(ath\232, the $@ part \(host name\))-.15 F .137
+(can be a colon-separated list of hosts instead of a single hostname.)102 675 R
+.138(This asks)5.138 F F2(sendmail)2.638 E F1 .138(to search the)2.638 F .161
+(list for the \214rst entry that is a)102 687 R -.25(va)-.2 G .161(ilable e).25
+F .16(xactly as though it were an MX record.)-.15 F .16(The intent is to route)
+5.16 F .737(internal traf)102 699 R .738(\214c through internal netw)-.25 F
+.738(orks without publishing an MX record to the net.)-.1 F .738(MX e)5.738 F
+(xpan-)-.15 E(sion is still done on the indi)102 711 Q(vidual items.)-.25 E EP
+%%Page: 59 54
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-59)452.9 60 Q 2.5(7.30. Aliases)87 96 R(Extended)2.5 E/F1 10
+/Times-Roman@0 SF 1.457(The implementation has been mer)127 112.2 R 1.457
+(ged with maps.)-.18 F 1.456(Among other things, this supports NIS-)6.457 F
+(based aliases.)102 124.2 Q F0 2.5(7.31. P)87 148.2 R
+(ortability and Security Enhancements)-.2 E F1 2.5(An)127 164.4 S
+(umber of internal changes ha)141.72 164.4 Q .3 -.15(ve b)-.2 H
+(een made to enhance portability).15 E(.)-.65 E(Se)127 180.6 Q -.15(ve)-.25 G
+(ral \214x).15 E(es ha)-.15 E .3 -.15(ve b)-.2 H
+(een made to increase the paranoia f).15 E(actor)-.1 E(.)-.55 E F0 2.5
+(7.32. Miscellaneous)87 204.6 R(Changes)2.5 E/F2 10/Times-Italic@0 SF(Sendmail)
+127 220.8 Q F1(writes a)2.5 E F2(/etc/sendmail.pid)2.5 E F1
+(\214le with the current process id of the SMTP daemon.)2.5 E -1 -.8(Tw o)127
+237 T 1.646(people using the same program in their .forw)4.946 F 1.647
+(ard \214le are considered dif)-.1 F 1.647(ferent so that)-.25 F
+(duplicate elimination doesn')102 249 Q 2.5(td)-.18 G(elete one of them.)225.98
+249 Q(The)127 265.2 Q F2(mailstats)3.181 E F1 .681
+(program prints mailer names and gets the location of the)3.181 F F2
+(sendmail.st)3.18 E F1 .68(\214le from)3.18 F F2(/etc/sendmail.cf)102 277.2 Q
+F1(.)A(Man)127 293.4 Q 2.5(ym)-.15 G(inor b)160.46 293.4 Q(ugs ha)-.2 E .3 -.15
+(ve b)-.2 H(een \214x).15 E
+(ed, such as handling of backslashes inside of quotes.)-.15 E 2.5(Ah)127 309.6
+S(ook \(ruleset 5\) has been added to allo)141.72 309.6 Q 2.5(wr)-.25 G -.25
+(ew)304.21 309.6 S(riting of local addresses after aliasing.).25 E F0 2.5(8. A)
+72 333.6 R(CKNO)-.55 E(WLEDGEMENTS)-.5 E F1(I')112 349.8 Q 2.036 -.15(ve w)-.5
+H(ork).05 E 1.737(ed on)-.1 F F2(sendmail)4.237 E F1 1.737(for man)4.237 F
+4.237(yy)-.15 G 1.737(ears, and man)267.501 349.8 R 4.237(ye)-.15 G(mplo)
+339.762 349.8 Q 1.737(yers ha)-.1 F 2.037 -.15(ve b)-.2 H 1.737
+(een remarkably patient).15 F .404(about letting me w)87 361.8 R .404
+(ork on a lar)-.1 F .404(ge project that w)-.18 F .403(as not part of my of)-.1
+F .403(\214cial job)-.25 F 5.403(.T)-.4 G .403(his includes time on the)407.388
+361.8 R(INGRES Project at Berk)87 373.8 Q(ele)-.1 E 1.3 -.65(y, a)-.15 H 2.5
+(tB).65 G(ritton Lee, and ag)222.75 373.8 Q(ain on the Mammoth Project at Berk)
+-.05 E(ele)-.1 E -.65(y.)-.15 G .453(Much of the second w)112 390 R -2.25 -.2
+(av e)-.1 H .453(of impro)3.153 F -.15(ve)-.15 G .453
+(ments should be credited to Bryan Costales of ICSI.).15 F .454(As he)5.454 F
+.781(passed me drafts of his book on)87 402 R F2(sendmail)3.281 E F1 3.281(Iw)
+3.281 G .781(as inspired to start w)274.741 402 R .781(orking on things ag)-.1
+F 3.281(ain. Bryan)-.05 F -.1(wa)3.281 G(s).1 E(also a)87 414 Q -.25(va)-.2 G
+(ilable to bounce ideas of).25 E 2.5(fo)-.25 G(f.)227.38 414 Q(Man)112 430.2 Q
+2.856 -.65(y, m)-.15 H(an).65 E 4.056(yp)-.15 G 1.556(eople contrib)172.212
+430.2 R 1.556(uted chunks of code and ideas to)-.2 F F2(sendmail)4.056 E F1
+6.556(.I)C 4.056(th)418.476 430.2 S 1.557(as pro)430.312 430.2 R -.15(ve)-.15 G
+4.057(nt).15 G 4.057(ob)477.006 430.2 S 4.057(ea)491.063 430.2 S .464
+(group netw)87 442.2 R .464(ork ef)-.1 F 2.964(fort. V)-.25 F .464
+(ersion 8 in particular w)-1.11 F .463(as a group project.)-.1 F .463
+(The follo)5.463 F .463(wing people made notable)-.25 F(contrib)87 454.2 Q
+(utions:)-.2 E -.25(Ke)127 470.4 S(ith Bostic, CSRG, Uni).25 E -.15(ve)-.25 G
+(rsity of California, Berk).15 E(ele)-.1 E(y)-.15 E(Michael J. Corrig)127 482.4
+Q(an, Uni)-.05 E -.15(ve)-.25 G(rsity of California, San Die).15 E(go)-.15 E
+(Bryan Costales, International Computer Science Institute)127 494.4 Q -.15(Pa)
+127 506.4 S -.5(..)132.298 500.4 S 2.5(r\()136.85 506.4 S(Pell\) Emanuelsson)
+146.01 506.4 Q(Craig Ev)127 518.4 Q(erhart, T)-.15 E(ransarc Corporation)-.35 E
+-.8(To)127 530.4 S 2.5(mI).8 G -.25(va)150.92 530.4 S 2.5(rH).25 G
+(elbekkmo, Norwe)173.16 530.4 Q(gian School of Economics)-.15 E
+(Allan E. Johannesen, WPI)127 542.4 Q(Jonathan Kamens, OpenV)127 554.4 Q
+(ision T)-.6 E(echnologies, Inc.)-.7 E -.8(Ta)127 566.4 S
+(kahiro Kanbe, Fuji Xerox Information Systems Co., Ltd.).8 E(Brian Kantor)127
+578.4 Q 2.5(,U)-.4 G(ni)191.31 578.4 Q -.15(ve)-.25 G
+(rsity of California, San Die).15 E(go)-.15 E(Murray S. K)127 590.4 Q(uchera)
+-.15 E(wy)-.15 E 2.5(,H)-.65 G(ookUp Communication Corp.)227.41 590.4 Q
+(Bruce Lilly)127 602.4 Q 2.5(,S)-.65 G(on)182.74 602.4 Q 2.5(yU)-.15 G(.S.)
+207.31 602.4 Q(Karl London)127 614.4 Q(Nakamura Motonori, K)127 626.4 Q
+(yoto Uni)-.25 E -.15(ve)-.25 G(rsity).15 E(John Gardiner Myers, Carne)127
+638.4 Q(gie Mellon Uni)-.15 E -.15(ve)-.25 G(rsity).15 E(Neil Rick)127 650.4 Q
+(ert, Northern Illinois Uni)-.1 E -.15(ve)-.25 G(rsity).15 E
+(Eric Schnoebelen, Con)127 662.4 Q .3 -.15(vex C)-.4 H(omputer Corp.).15 E
+(Eric W)127 674.4 Q(assenaar)-.8 E 2.5(,N)-.4 G
+(ational Institute for Nuclear and High Ener)200.49 674.4 Q(gy Ph)-.18 E
+(ysics, Amsterdam)-.05 E(Christophe W)127 686.4 Q(olfhugel, Herv)-.8 E 2.5(eS)
+-.15 G(chauer Consultants \(P)252.7 686.4 Q(aris\))-.15 E 2.687(Ia)87 702.6 S
+.187(pologize for an)97.457 702.6 R .188(yone I ha)-.15 F .488 -.15(ve o)-.2 H
+.188(mitted, misspelled, misattrib).15 F .188(uted, or otherwise missed.)-.2 F
+(Man)5.188 E 2.688(yo)-.15 G .188(ther peo-)467.992 702.6 R(ple ha)87 714.6 Q
+.3 -.15(ve c)-.2 H(ontrib).15 E(uted ideas, comments, and encouragement.)-.2 E
+2.5(Ia)5 G(ppreciate their contrib)338.06 714.6 Q(ution as well.)-.2 E EP
+%%Page: 60 55
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 12/Times-Bold@0 SF 3(APPENDIX A)257.172 98.4 R(COMMAND LINE FLA)224.832
+141.6 Q(GS)-.66 E/F1 10/Times-Roman@0 SF(Ar)97 201 Q
+(guments must be presented with \215ags before addresses.)-.18 E
+(The \215ags are:)5 E<ad62>72 217.2 Q/F2 10/Times-Italic@0 SF(x)A F1
+(Set operation mode to)144 217.2 Q F2(x)2.5 E F1 5(.O)C(peration modes are:)
+253.71 217.2 Q 12.22(mD)184 233.4 S(eli)211.22 233.4 Q -.15(ve)-.25 G 2.5(rm)
+.15 G(ail \(def)243.87 233.4 Q(ault\))-.1 E 16.11(sS)184 245.4 S
+(peak SMTP on input side)209.56 245.4 Q 15(dR)184 257.4 S(un as a daemon)210.67
+257.4 Q 17.22(tR)184 269.4 S(un in test mode)210.67 269.4 Q 15(vJ)184 281.4 S
+(ust v)207.89 281.4 Q(erify addresses, don')-.15 E 2.5(tc)-.18 G
+(ollect or deli)319.48 281.4 Q -.15(ve)-.25 G(r).15 E 17.22(iI)184 293.4 S
+(nitialize the alias database)207.33 293.4 Q 15(pP)184 305.4 S
+(rint the mail queue)209.56 305.4 Q<ad42>72 325.8 Q F2(type)A F1
+(Indicate body type.)144 325.8 Q<ad43>72 342 Q F2(\214le)A F1 .947(Use a dif)
+144 342 R .946(ferent con\214guration \214le.)-.25 F F2(Sendmail)5.946 E F1
+.946(runs as the in)3.446 F -.2(vo)-.4 G .946(king user \(rather than root\)).2
+F(when this \215ag is speci\214ed.)144 354 Q<ad64>72 370.2 Q F2(le)A(vel)-.15 E
+F1(Set deb)144 370.2 Q(ugging le)-.2 E -.15(ve)-.25 G(l.).15 E<ad66>72 386.4 Q
+F2(addr)2.5 E F1(The sender')144 386.4 Q 2.5(sm)-.55 G(achine address is)205.1
+386.4 Q F2(addr)2.5 E F1(.)A<ad46>72 402.6 Q F2(name)A F1
+(Sets the full name of this user to)144 402.6 Q F2(name)2.5 E F1(.)A<ad68>72
+418.8 Q F2(cnt)2.5 E F1 .725(Sets the \231hop count\232 to)144 418.8 R F2(cnt)
+3.225 E F1 5.725(.T)C .726
+(his represents the number of times this message has been)269.45 418.8 R .02
+(processed by)144 430.8 R F2(sendmail)2.52 E F1 .02(\(to the e)2.52 F .02
+(xtent that it is supported by the underlying netw)-.15 F(orks\).)-.1 E F2(Cnt)
+5.02 E F1 1.521
+(is incremented during processing, and if it reaches MAXHOP \(currently 30\))
+144 442.8 R F2(sendmail)4.021 E F1(thro)144 454.8 Q(ws a)-.25 E -.1(wa)-.15 G
+2.5(yt).1 G(he message with an error)199.6 454.8 Q(.)-.55 E 58.86(\255n Don')72
+471 R 2.5(td)-.18 G 2.5(oa)174.65 471 S(liasing or forw)186.59 471 Q(arding.)
+-.1 E<ad72>72 487.2 Q F2(addr)2.5 E F1(An obsolete form of)144 487.2 Q/F3 10
+/Times-Bold@0 SF<ad66>2.5 E F1(.)A<ad6f>72 503.4 Q F2 1.666(xv)C(alue)-1.666 E
+F1(Set option)144 503.4 Q F2(x)2.5 E F1(to the speci\214ed)2.5 E F2(value)2.5 E
+F1 5(.T)C(hese options are described in Appendix B.)292.6 503.4 Q<ad70>72 519.6
+Q F2(pr)A(otocol)-.45 E F1 .401(Set the sending protocol.)144 519.6 R .401
+(Programs are encouraged to set this.)5.401 F .4(The protocol \214eld can be)
+5.401 F .114(in the form)144 531.6 R F2(pr)2.614 E(otocol)-.45 E F3(:)A F2
+(host)A F1 .114(to set both the sending protocol and sending host.)2.614 F -.15
+(Fo)5.115 G 2.615(re).15 G(xample,)472.06 531.6 Q 2.147(\231\255pUUCP:uunet\
+\232 sets the sending protocol to UUCP and the sending host to uunet.)144 543.6
+R .973(\(Some e)144 555.6 R .974
+(xisting programs use \255oM to set the r and s macros; this is equi)-.15 F
+-.25(va)-.25 G .974(lent to using).25 F(\255p.\))144 567.6 Q<ad71>72 583.8 Q F2
+(time)A F1 -.35(Tr)144 583.8 S 3.168(yt).35 G 3.167(op)164.038 583.8 S .667
+(rocess the queued up mail.)177.205 583.8 R .667(If the time is gi)5.667 F -.15
+(ve)-.25 G .667(n, a).15 F F2(sendmail)3.167 E F1 .667(will run through the)
+3.167 F(queue at the speci\214ed interv)144 595.8 Q(al to deli)-.25 E -.15(ve)
+-.25 G 2.5(rq).15 G(ueued mail; otherwise, it only runs once.)310.82 595.8 Q
+<ad71>72 612 Q F2(Xstring)A F1 .312
+(Run the queue once, limiting the jobs to those matching)144 612 R F2(Xstring)
+2.813 E F1 5.313(.T)C .313(he k)416.325 612 R .613 -.15(ey l)-.1 H(etter).15 E
+F2(X)2.813 E F1 .313(can be)2.813 F F3(I)144 624 Q F1 .671
+(to limit based on queue identi\214er)3.171 F(,)-.4 E F3(R)3.171 E F1 .67
+(to limit based on recipient, or)3.171 F F3(S)3.17 E F1 .67(to limit based on)
+3.17 F(sender)144 636 Q 6.053(.A)-.55 G 1.054
+(particular queued job is accepted if one of the corresponding addresses con-)
+188.876 636 R(tains the indicated)144 648 Q F2(string)2.5 E F1(.)A 61.08
+(\255t Read)72 664.2 R .752(the header for \231T)3.252 F .752
+(o:\232, \231Cc:\232, and \231Bcc:\232 lines, and send to e)-.8 F -.15(ve)-.25
+G .752(ryone listed in those).15 F 2.539(lists. The)144 676.2 R .039
+(\231Bcc:\232 line will be deleted before sending.)2.539 F(An)5.039 E 2.539(ya)
+-.15 G .04(ddresses in the ar)385.31 676.2 R .04(gument v)-.18 F(ec-)-.15 E
+(tor will be deleted from the send list.)144 688.2 Q<ad58>72 704.4 Q F2(lo)3.18
+E(g\214le)-.1 E F1 .68(Log all traf)144.68 704.4 R .68(\214c in and out of)-.25
+F F2(sendmail)3.179 E F1 .679(in the indicated)3.179 F F2(lo)3.179 E(g\214le)
+-.1 E F1 .679(for deb)3.179 F .679(ugging mailer prob-)-.2 F 2.5(lems. This)144
+716.4 R(produces a lot of data v)2.5 E
+(ery quickly and should be used sparingly)-.15 E(.)-.65 E F3 193.36
+(SMM:08-60 Sendmail)72 756 R(Installation and Operation Guide)2.5 E EP
+%%Page: 61 56
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-61)452.9 60 Q/F1 10/Times-Roman@0 SF .637
+(There are a number of options that may be speci\214ed as primiti)97 96 R .938
+-.15(ve \215)-.25 H 3.138(ags. These).15 F .638(are the e, i, m, and v)3.138 F
+2.5(options. Also,)72 108 R(the f option may be speci\214ed as the)2.5 E F0
+<ad73>2.5 E F1(\215ag.)2.5 E EP
+%%Page: 62 57
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 12/Times-Bold@0 SF 3(APPENDIX B)250.002 98.4 R -.12(QU)220.29 141.6 S
+(EUE FILE FORMA).12 E(TS)-1.14 E/F1 10/Times-Roman@0 SF .292
+(This appendix describes the format of the queue \214les.)97 201 R .292
+(These \214les li)5.292 F .592 -.15(ve i)-.25 H 2.792(nt).15 G .291
+(he directory de\214ned by the)395.636 201 R/F2 10/Times-Bold@0 SF(Q)72 213 Q
+F1(option in the)2.5 E/F3 10/Times-Italic@0 SF(sendmail.cf)2.5 E F1
+(\214le, usually)2.5 E F3(/var/spool/mqueue)2.5 E F1(or)2.5 E F3
+(/usr/spool/mqueue)2.5 E F1(.)A .229(All queue \214les ha)97 229.2 R .529 -.15
+(ve t)-.2 H .229(he name).15 F F3(x)2.729 E F2(f)1.666 E F3(AAA99999)A F1
+(where)2.73 E F3(AAA99999)2.73 E F1 .23(is the)2.73 F F3(id)2.73 E F1 .23
+(for this message and the)2.73 F F3(x)2.73 E F1 .23(is a)2.73 F 3.601
+(type. The)72 241.2 R 1.101
+(\214rst letter of the id encodes the hour of the day that the message w)3.601
+F 1.101(as recei)-.1 F -.15(ve)-.25 G 3.601(db).15 G 3.601(yt)451.798 241.2 S
+1.101(he system)463.179 241.2 R .551
+(\(with A being the hour between midnight and 1:00AM\).)72 253.2 R .552
+(All \214les with the same id collecti)5.552 F -.15(ve)-.25 G .552
+(ly de\214ne one).15 F(message.)72 265.2 Q(The types are:)97 281.4 Q 31(dT)72
+297.6 S(he data \214le.)114.11 297.6 Q(The message body \(e)5 E
+(xcluding the header\) is k)-.15 E(ept in this \214le.)-.1 E 33.22(lT)72 313.8
+S .312(he lock \214le.)114.11 313.8 R .312(If this \214le e)5.312 F .311
+(xists, the job is currently being processed, and a queue run will not pro-)
+-.15 F .523(cess the \214le.)108 325.8 R -.15(Fo)5.524 G 3.024(rt).15 G .524
+(hat reason, an e)183.274 325.8 R(xtraneous)-.15 E F2(lf)3.024 E F1 .524
+(\214le can cause a job to apparently disappear \(it will)3.024 F .285(not e)
+108 337.8 R -.15(ve)-.25 G 2.785(nt).15 G .284(ime out!\).)147.61 337.8 R
+([Actually)5.284 E 2.784(,t)-.65 G .284
+(his \214le is obsolete on most systems that support the)237.802 337.8 R F2
+(\215ock)2.784 E F1(or)2.784 E F2(lockf)2.784 E F1(system calls.])108 349.8 Q
+31(nT)72 366 S .348(his \214le is created when an id is being created.)114.11
+366 R .348(It is a separate \214le to insure that no mail can e)5.348 F -.15
+(ve)-.25 G(r).15 E .805(be destro)108 378 R .805(yed due to a race condition.)
+-.1 F .805(It should e)5.805 F .805(xist for no more than a fe)-.15 F 3.305(wm)
+-.25 G .805(illiseconds at an)433.1 378 R(y)-.15 E(gi)108 390 Q -.15(ve)-.25 G
+2.5(nt).15 G 2.5(ime. [This)135.1 390 R(is only used on old v)2.5 E(ersions of)
+-.15 E F3(sendmail)2.5 E F1 2.5(;i)C 2.5(ti)349.95 390 S 2.5(sn)358.01 390 S
+(ot used on ne)369.4 390 Q(wer v)-.25 E(ersions.])-.15 E 31(qT)72 406.2 S
+(he queue control \214le.)114.11 406.2 Q
+(This \214le contains the information necessary to process the job)5 E(.)-.4 E
+33.22(tA)72 422.4 S .344(temporary \214le.)118.064 422.4 R .344
+(These are an image of the)5.344 F F2(qf)2.844 E F1 .344
+(\214le when it is being reb)2.844 F 2.845(uilt. It)-.2 F .345
+(should be renamed)2.845 F(to a)108 434.4 Q F2(qf)2.5 E F1(\214le v)2.5 E
+(ery quickly)-.15 E(.)-.65 E 31(xA)72 450.6 S .567(transcript \214le, e)118.287
+450.6 R .567(xisting during the life of a session sho)-.15 F .566(wing e)-.25 F
+-.15(ve)-.25 G .566(rything that happens during that).15 F(session.)108 462.6 Q
+(The)97 478.8 Q F2(qf)3.333 E F1 .833
+(\214le is structured as a series of lines each be)3.333 F .834
+(ginning with a code letter)-.15 F 5.834(.T)-.55 G .834(he lines are as fol-)
+427.354 478.8 R(lo)72 490.8 Q(ws:)-.25 E 28.78(DT)72 507 S
+(he name of the data \214le.)114.11 507 Q
+(There may only be one of these lines.)5 E 28.78(HA)72 523.2 S .33
+(header de\214nition.)118.05 523.2 R .33(There may be an)5.33 F 2.829(yn)-.15 G
+.329(umber of these lines.)274.289 523.2 R .329(The order is important: the)
+5.329 F 2.829(yr)-.15 G(epre-)483.46 523.2 Q .046
+(sent the order in the \214nal message.)108 535.2 R .046
+(These use the same syntax as header de\214nitions in the con\214gu-)5.046 F
+(ration \214le.)108 547.2 Q 29.33(CT)72 563.4 S .575(he controlling address.)
+114.11 563.4 R .575(The syntax is \231localuser:aliasname\232.)5.575 F .575
+(Recipient addresses follo)5.575 F .575(wing this)-.25 F 2.814
+(line will be \215agged so that deli)108 575.4 R -.15(ve)-.25 G 2.814
+(ries will be run as the).15 F F3(localuser)5.314 E F1 2.814
+(\(a user name from the)5.314 F .562(/etc/passwd \214le\);)108 587.4 R F3
+(aliasname)3.062 E F1 .561(is the name of the alias that e)3.062 F .561
+(xpanded to this address \(used for print-)-.15 F(ing messages\).)108 599.4 Q
+29.33(RA)72 615.6 S .705(recipient address.)118.425 615.6 R .705
+(This will normally be completely aliased, b)5.705 F .705
+(ut is actually realiased when the)-.2 F(job is processed.)108 627.6 Q
+(There will be one line for each recipient.)5 E 30.44(ST)72 643.8 S
+(he sender address.)114.11 643.8 Q(There may only be one of these lines.)5 E
+29.89(EA)72 660 S 3.742(ne)115.22 660 S 1.242(rror address.)128.402 660 R 1.242
+(If an)6.242 F 3.742(ys)-.15 G 1.241(uch lines e)218.19 660 R 1.241(xist, the)
+-.15 F 3.741(yr)-.15 G 1.241(epresent the addresses that should recei)308.124
+660 R 1.541 -.15(ve e)-.25 H(rror).15 E(messages.)108 672 Q 29.89(TT)72 688.2 S
+(he job creation time.)114.11 688.2 Q
+(This is used to compute when to time out the job)5 E(.)-.4 E 30.44(PT)72 704.4
+S .113(he current message priority)114.11 704.4 R 5.113(.T)-.65 G .113
+(his is used to order the queue.)236.662 704.4 R .114(Higher numbers mean lo)
+5.114 F .114(wer priori-)-.25 F 3.677(ties. The)108 716.4 R 1.176
+(priority changes as the message sits in the queue.)3.677 F 1.176
+(The initial priority depends on the)6.176 F F2 193.36(SMM:08-62 Sendmail)72
+756 R(Installation and Operation Guide)2.5 E EP
+%%Page: 63 58
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-63)452.9 60 Q/F1 10/Times-Roman@0 SF
+(message class and the size of the message.)108 96 Q 27.11(MA)72 112.2 S 2.703
+(message. This)117.923 112.2 R .203(line is printed by the)2.703 F/F2 10
+/Times-Italic@0 SF(mailq)2.703 E F1 .204
+(command, and is generally used to store status infor)2.704 F(-)-.2 E 2.5
+(mation. It)108 124.2 R(can contain an)2.5 E 2.5(yt)-.15 G -.15(ex)219.78 124.2
+S(t.).15 E 30.44(FF)72 140.4 S .044
+(lag bits, represented as one letter per \215ag.)113.56 140.4 R .043
+(De\214ned \215ag bits are)5.043 F F0(r)2.543 E F1 .043
+(indicating that this is a response)2.543 F .142(message and)108 152.4 R F0(w)
+2.642 E F1 .142(indicating that a w)2.642 F .143
+(arning message has been sent announcing that the mail has been)-.1 F(delayed.)
+108 164.4 Q 31($A)72 180.6 S .83(macro de\214nition.)118.55 180.6 R .83(The v)
+5.83 F .829(alues of certain macros \(as of this writing, only)-.25 F F0($r)
+3.329 E F1(and)3.329 E F0($s)3.329 E F1 3.329(\)a)C .829(re passed)466.241
+180.6 R(through to the queue run phase.)108 192.6 Q 29.33(BT)72 208.8 S .924
+(he body type.)114.11 208.8 R .925(The remainder of the line is a te)5.924 F
+.925(xt string de\214ning the body type.)-.15 F .925(If this \214eld is)5.925 F
+.009(missing, the body type is assumed to be \231unde\214ned\232 and no specia\
+l processing is attempted.)108 220.8 R(Le)5.008 E -.05(ga)-.15 G(l).05 E -.25
+(va)108 232.8 S(lues are \2317BIT\232 and \2318BITMIME\232.).25 E 4.072
+(As an e)97 249 R 4.072(xample, the follo)-.15 F 4.073
+(wing is a queue \214le sent to \231eric@mammoth.Berk)-.25 F(ele)-.1 E -.65(y.)
+-.15 G 4.073(EDU\232 and).65 F(\231bostic@ok)72 263 Q(eef)-.1 E(fe.CS.Berk)-.25
+E(ele)-.1 E -.65(y.)-.15 G(EDU\232).65 E/F3 7/Times-Roman@0 SF(1)219.09 259 Q
+F1(:)222.59 263 Q(P835771)112 279.2 Q(T404261372)112 291.2 Q(DdfAAA13557)112
+303.2 Q(Seric)112 315.2 Q(Eo)112 327.2 Q(wner)-.25 E(-sendmail@v)-.2 E
+(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E(Ceric:sendmail@v)112
+339.2 Q(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E
+(Reric@mammoth.Berk)112 351.2 Q(ele)-.1 E -.65(y.)-.15 G(EDU).65 E(Rbostic@ok)
+112 363.2 Q(eef)-.1 E(fe.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU).65 E
+(H?P?return-path: <o)112 375.2 Q(wner)-.25 E(-sendmail@v)-.2 E(angogh.CS.Berk)
+-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU>).65 E(Hrecei)112 387.2 Q -.15(ve)-.25 G
+(d: by v).15 E(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G
+(EDU \(5.108/2.7\) id AAA06703;).65 E(Fri, 17 Jul 92 00:28:55 -0700)132 399.2 Q
+(Hrecei)112 411.2 Q -.15(ve)-.25 G(d: from mail.CS.Berk).15 E(ele)-.1 E -.65
+(y.)-.15 G(EDU by v).65 E(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G
+(EDU \(5.108/2.7\)).65 E(id AAA06698; Fri, 17 Jul 92 00:28:54 -0700)132 423.2 Q
+(Hrecei)112 435.2 Q -.15(ve)-.25 G(d: from [128.32.31.21] by mail.CS.Berk).15 E
+(ele)-.1 E -.65(y.)-.15 G(EDU \(5.96/2.5\)).65 E
+(id AA22777; Fri, 17 Jul 92 03:29:14 -0400)132 447.2 Q(Hrecei)112 459.2 Q -.15
+(ve)-.25 G(d: by foo.bar).15 E(.baz.de \(5.57/Ultrix3.0-C\))-.55 E
+(id AA22757; Fri, 17 Jul 92 09:31:25 GMT)132 471.2 Q(H?F?from: eric@foo.bar)112
+483.2 Q(.baz.de \(Eric Allman\))-.55 E(H?x?full-name: Eric Allman)112 495.2 Q
+(Hmessage-id: <9207170931.AA22757@foo.bar)112 507.2 Q(.baz.de>)-.55 E(HT)112
+519.2 Q(o: sendmail@v)-.8 E(angogh.CS.Berk)-.25 E(ele)-.1 E -.65(y.)-.15 G(EDU)
+.65 E(Hsubject: this is an e)112 531.2 Q(xample message)-.15 E 1.083(This sho)
+72 547.4 R 1.084(ws the name of the data \214le, the person who sent the messa\
+ge, the submission time \(in seconds)-.25 F .26
+(since January 1, 1970\), the message priority)72 559.4 R 2.76(,t)-.65 G .259
+(he message class, the recipients, and the headers for the mes-)257.03 559.4 R
+(sage.)72 571.4 Q .32 LW 76 669.2 72 669.2 DL 80 669.2 76 669.2 DL 84 669.2 80
+669.2 DL 88 669.2 84 669.2 DL 92 669.2 88 669.2 DL 96 669.2 92 669.2 DL 100
+669.2 96 669.2 DL 104 669.2 100 669.2 DL 108 669.2 104 669.2 DL 112 669.2 108
+669.2 DL 116 669.2 112 669.2 DL 120 669.2 116 669.2 DL 124 669.2 120 669.2 DL
+128 669.2 124 669.2 DL 132 669.2 128 669.2 DL 136 669.2 132 669.2 DL 140 669.2
+136 669.2 DL 144 669.2 140 669.2 DL 148 669.2 144 669.2 DL 152 669.2 148 669.2
+DL 156 669.2 152 669.2 DL 160 669.2 156 669.2 DL 164 669.2 160 669.2 DL 168
+669.2 164 669.2 DL 172 669.2 168 669.2 DL 176 669.2 172 669.2 DL 180 669.2 176
+669.2 DL 184 669.2 180 669.2 DL 188 669.2 184 669.2 DL 192 669.2 188 669.2 DL
+196 669.2 192 669.2 DL 200 669.2 196 669.2 DL 204 669.2 200 669.2 DL 208 669.2
+204 669.2 DL 212 669.2 208 669.2 DL 216 669.2 212 669.2 DL/F4 5/Times-Roman@0
+SF(1)93.6 679.6 Q/F5 8/Times-Roman@0 SF .719(This e)3.2 J .719
+(xample is contri)-.12 F -.12(ve)-.2 G 2.719(da).12 G .719
+(nd probably inaccurate for your en)186.968 682.8 R 2.719(vironment. Glance)
+-.32 F -.12(ove)2.718 G 2.718(ri).12 G 2.718(tt)384.998 682.8 S 2.718(og)
+392.164 682.8 S .718(et an idea; nothing can replace)402.882 682.8 R
+(looking at what your o)72 692.4 Q(wn system generates.)-.2 E EP
+%%Page: 64 59
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 12/Times-Bold@0 SF 3(APPENDIX C)249.672 98.4 R(SUMMAR)198.282 141.6 Q 3(YO)
+-.42 G 3(FS)274.182 141.6 S(UPPOR)291.186 141.6 Q 3(TF)-.48 G(ILES)350.37 141.6
+Q/F1 10/Times-Roman@0 SF 1.519(This is a summary of the support \214les that)97
+201 R/F2 10/Times-Italic@0 SF(sendmail)4.019 E F1 1.52(creates or generates.)
+4.019 F(Man)6.52 E 4.02(yo)-.15 G 4.02(ft)444.74 201 S 1.52(hese can be)454.87
+201 R(changed by editing the sendmail.cf \214le; check there to \214nd the act\
+ual pathnames.)72 213 Q(/usr/sbin/sendmail)72 229.2 Q(The binary of)144 241.2 Q
+F2(sendmail)2.5 E F1(.)A(/usr/bin/ne)72 257.4 Q -.1(wa)-.25 G(liases).1 E 3.735
+(Al)144 269.4 S 1.235
+(ink to /usr/sbin/sendmail; causes the alias database to be reb)157.735 269.4 R
+3.734(uilt. Running)-.2 F 1.234(this pro-)3.734 F(gram is completely equi)144
+281.4 Q -.25(va)-.25 G(lent to gi).25 E(ving)-.25 E F2(sendmail)2.5 E F1(the)
+2.5 E/F3 10/Times-Bold@0 SF(\255bi)2.5 E F1(\215ag.)2.5 E 13.38
+(/usr/bin/mailq Prints)72 297.6 R 3.702(al)3.702 G 1.202
+(isting of the mail queue.)181.964 297.6 R 1.203(This program is equi)6.202 F
+-.25(va)-.25 G 1.203(lent to using the).25 F F3(\255bp)3.703 E F1 1.203
+(\215ag to)3.703 F F2(sendmail)144 309.6 Q F1(.)A 5.9(/etc/sendmail.cf The)72
+325.8 R(con\214guration \214le, in te)2.5 E(xtual form.)-.15 E
+(/usr/lib/sendmail.hf)72 342 Q(The SMTP help \214le.)144 354 Q 7
+(/etc/sendmail.st A)72 370.2 R(statistics \214le; need not be present.)2.5 E
+.89(/etc/sendmail.pid Created)72 386.4 R .318
+(in daemon mode; it contains the process id of the current SMTP daemon.)2.818 F
+.318(If you)5.318 F .337(use this in scripts; use `)144 398.4 R .337
+(`head \2551')-.74 F 2.838('t)-.74 G 2.838(og)285.78 398.4 S .338
+(et just the \214rst line; later v)298.618 398.4 R .338(ersions of)-.15 F F2
+(sendmail)2.838 E F1(may)2.838 E(add information to subsequent lines.)144 410.4
+Q 25.62(/etc/aliases The)72 426.6 R(te)2.5 E(xtual v)-.15 E
+(ersion of the alias \214le.)-.15 E(/etc/aliases.{pag,dir})72 442.8 Q
+(The alias \214le in)144 454.8 Q F2(dbm)2.5 E F1(\(3\) format.)1.666 E(/v)72
+471 Q(ar/spool/mqueue)-.25 E
+(The directory in which the mail queue and temporary \214les reside.)144 483 Q
+(/v)72 499.2 Q(ar/spool/mqueue/qf*)-.25 E
+(Control \(queue\) \214les for messages.)144 511.2 Q(/v)72 527.4 Q
+(ar/spool/mqueue/df*)-.25 E(Data \214les.)144 539.4 Q(/v)72 555.6 Q
+(ar/spool/mqueue/tf*)-.25 E -.7(Te)144 567.6 S(mporary v).7 E
+(ersions of the qf \214les, used during queue \214le reb)-.15 E(uild.)-.2 E(/v)
+72 583.8 Q(ar/spool/mqueue/xf*)-.25 E 2.5(At)144 595.8 S
+(ranscript of the current session.)156.5 595.8 Q F3 193.36(SMM:08-64 Sendmail)
+72 756 R(Installation and Operation Guide)2.5 E EP
+%%Page: 2 60
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 198.36(SMM:08-2 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF
+(This page intentionally left blank;)256.225 300 Q
+(replace it with a blank sheet for double-sided output.)218.6 312 Q EP
+%%Page: 3 61
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-3)457.9 60 Q/F1 12/Times-Roman@0 SF -1.116(TA)263.226 98.4 S
+(BLE OF CONTENTS)1.116 E/F2 10/Times-Roman@0 SF 2.5(1. B)72 124.8 R(ASIC INST)
+-.35 E(ALLA)-.93 E 1.18(TION .................................................\
+..............................................................)-1.11 F(7)499
+124.8 Q 2.5(1.1. Compiling)87 139.2 R .43(Sendmail ...........................\
+..............................................................................\
+.....)2.5 F(7)499 139.2 Q 2.5(1.1.1. Old)102 153.6 R -.15(ve)2.5 G
+(rsions of mak).15 E 2.93(e.)-.1 G 28.5(......................................\
+............................................................. 7)220.5 153.6 R
+2.5(1.1.2. Compilation)102 168 R 2.1(\215ags .................................\
+........................................................................)2.5 F
+(7)499 168 Q 2.5(1.1.3. Compilation)102 182.4 R(and installation)2.5 E 28.5(..\
+..............................................................................\
+........ 8)4.6 F 2.5(1.2. Con\214guration)87 196.8 R .99(Files ...............\
+..............................................................................\
+...................)2.5 F(8)499 196.8 Q 2.5(1.3. Details)87 211.2 R
+(of Installation Files)2.5 E 28.5(............................................\
+....................................................... 9)4.89 F 2.5
+(1.3.1. /usr/sbin/sendmail)102 225.6 R 28.5(..................................\
+....................................................................... 9)2.66
+F 2.5(1.3.2. /etc/sendmail.cf)102 240 R 23.5(.................................\
+........................................................................... 10)
+4.9 F 2.5(1.3.3. /usr/bin/ne)102 254.4 R -.1(wa)-.25 G 2.19(liases ...........\
+..............................................................................\
+..............).1 F(10)494 254.4 Q 2.5(1.3.4. /v)102 268.8 R 1.81(ar/spool/mqu\
+eue ..........................................................................\
+..............................)-.25 F(10)494 268.8 Q 2.5(1.3.5. /etc/aliases*)
+102 283.2 R 23.5(.............................................................\
+..................................................... 10)4.62 F 2.5
+(1.3.6. /etc/rc)102 297.6 R 23.5(.............................................\
+..............................................................................\
+. 10)3.51 F 2.5(1.3.7. /usr/lib/sendmail.hf)102 312 R 23.5(...................\
+..............................................................................\
+...... 12)2.94 F 2.5(1.3.8. /etc/sendmail.st)102 326.4 R 23.5(................\
+..............................................................................\
+............... 12)3.5 F 2.5(1.3.9. /usr/bin/ne)102 340.8 R -.1(wa)-.25 G 2.19
+(liases ......................................................................\
+.................................).1 F(12)494 340.8 Q 2.5
+(1.3.10. /usr/bin/mailq)102 355.2 R 23.5(.....................................\
+........................................................................ 12)
+4.88 F 2.5(2. NORMAL)72 369.6 R(OPERA)2.5 E 1.56(TIONS .......................\
+..............................................................................\
+........)-1.11 F(12)494 369.6 Q 2.5(2.1. The)87 384 R(System Log)2.5 E 23.5(..\
+..............................................................................\
+.................................... 12)4.89 F 2.5(2.1.1. F)102 398.4 R 2.26(o\
+rmat .........................................................................\
+.................................................)-.15 F(12)494 398.4 Q 2.5
+(2.1.2. Le)102 412.8 R -.15(ve)-.25 G 2.24(ls ................................\
+..............................................................................\
+.............).15 F(12)494 412.8 Q 2.5(2.2. The)87 427.2 R(Mail Queue)2.5 E
+23.5(.........................................................................\
+............................................ 12)2.96 F 2.5(2.2.1. Printing)102
+441.6 R(the queue)2.5 E 23.5(.................................................\
+........................................................ 13)2.67 F 2.5
+(2.2.2. F)102 456 R(orcing the queue)-.15 E 23.5(.............................\
+............................................................................ 1\
+3)3.94 F 2.5(2.3. The)87 470.4 R(Alias Database)2.5 E 23.5(...................\
+..............................................................................\
+............... 13)2.69 F 2.5(2.3.1. Reb)102 484.8 R
+(uilding the alias database)-.2 E 23.5(.......................................\
+................................................ 14)4.27 F 2.5
+(2.3.2. Potential)102 499.2 R .72(problems ...................................\
+.....................................................................)2.5 F(14)
+494 499.2 Q 2.5(2.3.3. List)102 513.6 R -.25(ow)2.5 G 1.81(ners ..............\
+..............................................................................\
+.......................).25 F(14)494 513.6 Q 2.5(2.4. User)87 528 R
+(Information Database)2.5 E 23.5(.............................................\
+....................................................... 15)2.7 F 2.5(2.5. Per)
+87 542.4 R(-User F)-.2 E(orw)-.15 E(arding \(.forw)-.1 E(ard Files\))-.1 E 23.5
+(.............................................................................\
+...... 15)4.09 F 2.5(2.6. Special)87 556.8 R(Header Lines)2.5 E 23.5(.........\
+..............................................................................\
+...................... 15)2.97 F 2.5(2.6.1. Return-Receipt-T)102 571.2 R .98(o\
+: ............................................................................\
+...........................)-.8 F(15)494 571.2 Q 2.5(2.6.2. Errors-T)102 585.6
+R 2.09(o: ....................................................................\
+.................................................)-.8 F(16)494 585.6 Q 2.5
+(2.6.3. Apparently-T)102 600 R 2.09(o: .......................................\
+......................................................................)-.8 F
+(16)494 600 Q 2.5(2.7. IDENT)87 614.4 R(Protocol Support)2.5 E 23.5(..........\
+..............................................................................\
+............... 16)2.95 F 2.5(3. ARGUMENTS)72 628.8 R 23.5(...................\
+..............................................................................\
+.............................. 16)3.78 F 2.5(3.1. Queue)87 643.2 R(Interv)2.5 E
+1.55(al ......................................................................\
+.................................................)-.25 F(16)494 643.2 Q 2.5
+(3.2. Daemon)87 657.6 R 1.29(Mode ............................................\
+...........................................................................)2.5
+F(17)494 657.6 Q 2.5(3.3. F)87 672 R(orcing the Queue)-.15 E 23.5(............\
+..............................................................................\
+....................... 17)4.22 F 2.5(3.4. Deb)87 686.4 R 1.76(ugging ........\
+..............................................................................\
+.......................................)-.2 F(17)494 686.4 Q 2.5(3.5. T)87
+700.8 R(rying a Dif)-.35 E(ferent Con\214guration File)-.25 E 23.5(...........\
+........................................................................ 17)
+4.67 F 2.5(3.6. Changing)87 715.2 R(the V)2.5 E(alues of Options)-1.11 E 23.5(\
+..............................................................................\
+.............. 17)3.23 F EP
+%%Page: 4 62
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 198.36(SMM:08-4 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 2.5
+(3.7. Logging)87 96 R -.35(Tr)2.5 G(af).35 E .5(\214c ........................\
+..............................................................................\
+................)-.25 F(18)494 96 Q 2.5(3.8. Dumping)87 110.4 R .72(State ....\
+..............................................................................\
+.....................................)2.5 F(18)494 110.4 Q 2.5(4. TUNING)72
+124.8 R 23.5(.................................................................\
+........................................................................ 18)
+2.68 F 2.5(4.1. T)87 139.2 R 1.07(imeouts ....................................\
+..............................................................................\
+..............)-.35 F(18)494 139.2 Q 2.5(4.1.1. Queue)102 153.6 R(interv)2.5 E
+2.1(al .......................................................................\
+.......................................)-.25 F(18)494 153.6 Q 2.5(4.1.2. Read)
+102 168 R 1(timeouts .........................................................\
+......................................................)2.5 F(18)494 168 Q 2.5
+(4.1.3. Message)102 182.4 R 1.56(timeouts ....................................\
+.....................................................................)2.5 F(19)
+494 182.4 Q 2.5(4.2. F)87 196.8 R(orking During Queue Runs)-.15 E 23.5(.......\
+..............................................................................\
+............ 20)4.49 F 2.5(4.3. Queue)87 211.2 R .73(Priorities ..............\
+..............................................................................\
+.........................)2.5 F(20)494 211.2 Q 2.5(4.4. Load)87 225.6 R .44(Li\
+miting .......................................................................\
+.................................................)2.5 F(20)494 225.6 Q 2.5
+(4.5. Deli)87 240 R -.15(ve)-.25 G(ry Mode).15 E 23.5(........................\
+..............................................................................\
+................. 21)3.08 F 2.5(4.6. Log)87 254.4 R(Le)2.5 E -.15(ve)-.25 G
+2.52(l.).15 G 23.5(...........................................................\
+................................................................... 21)153
+254.4 R 2.5(4.7. File)87 268.8 R .72(Modes ...................................\
+..............................................................................\
+............)2.5 F(22)494 268.8 Q 2.5(4.7.1. T)102 283.2 R 2.5(os)-.8 G
+(uid or not to suid?)146.2 283.2 Q 23.5(......................................\
+........................................................... 22)6.52 F 2.5
+(4.7.2. Should)102 297.6 R(my alias database be writable?)2.5 E 23.5
+(........................................................................ 22)
+5.47 F 2.5(4.8. Connection)87 312 R 1.56(Caching .............................\
+..............................................................................\
+...)2.5 F(22)494 312 Q 2.5(4.9. Name)87 326.4 R(Serv)2.5 E(er Access)-.15 E
+23.5(.........................................................................\
+..................................... 22)2.85 F 2.5(4.10. Mo)87 340.8 R
+(ving the Per)-.15 E(-User F)-.2 E(orw)-.15 E(ard Files)-.1 E 23.5(...........\
+......................................................................... 23)
+3.84 F 2.5(4.11. Free)87 355.2 R 1.85(Space ..................................\
+..............................................................................\
+...........)2.5 F(23)494 355.2 Q 2.5(4.12. Pri)87 369.6 R -.25(va)-.25 G .3
+-.15(cy F).25 H 1.93(lags ....................................................\
+...................................................................).15 F(24)
+494 369.6 Q 2.5(4.13. Send)87 384 R(to Me T)2.5 E 2.08(oo ....................\
+..............................................................................\
+.................)-.8 F(24)494 384 Q 2.5(5. THE)72 398.4 R
+(WHOLE SCOOP ON THE CONFIGURA)2.5 E(TION FILE)-1.11 E 23.5
+(........................................................ 24)4.64 F 2.5
+(5.1. Con\214guration)87 412.8 R(File Lines)2.5 E 23.5(.......................\
+..............................................................................\
+... 24)2.66 F 2.5(5.1.1. R)102 427.2 R(and S \212 re)2.5 E(writing rules)-.25 E
+23.5(.........................................................................\
+................... 24)3.48 F 2.5(5.1.1.1. The)117 441.6 R(left hand side)2.5 E
+23.5(.........................................................................\
+....................... 25)4.07 F 2.5(5.1.1.2. The)117 456 R(right hand side)
+2.5 E 23.5(...................................................................\
+........................... 25)3.51 F 2.5(5.1.1.3. Semantics)117 470.4 R(of re)
+2.5 E(writing rule sets)-.25 E 23.5
+(.......................................................................... 26)
+4.6 F 2.5(5.1.1.4. IPC)117 484.8 R 1(mailers .................................\
+.........................................................................)2.5 F
+(27)494 484.8 Q 2.5(5.1.2. D)102 499.2 R 2.5<8a64>2.5 G(e\214ne macro)156.72
+499.2 Q 23.5(.................................................................\
+....................................... 28)4.35 F 2.5(5.1.3. C)102 513.6 R
+(and F \212 de\214ne classes)2.5 E 23.5(......................................\
+....................................................... 30)4.62 F 2.5(5.1.4. M)
+102 528 R 2.5<8a64>2.5 G(e\214ne mailer)158.39 528 Q 23.5(....................\
+..............................................................................\
+..... 31)4.62 F 2.5(5.1.5. H)102 542.4 R 2.5<8a64>2.5 G(e\214ne header)156.72
+542.4 Q 23.5(.................................................................\
+....................................... 33)2.69 F 2.5(5.1.6. O)102 556.8 R 2.5
+<8a73>2.5 G(et option)155.61 556.8 Q 23.5(....................................\
+......................................................................... 33)
+4.61 F 2.5(5.1.7. P)102 571.2 R 2.5<8a70>2.5 G(recedence de\214nitions)155.06
+571.2 Q 23.5(.................................................................\
+......................... 38)3.24 F 2.5(5.1.8. V)102 585.6 R 2.5<8a63>2.5 G
+(on\214guration v)156.16 585.6 Q(ersion le)-.15 E -.15(ve)-.25 G 4.62(l.).15 G
+23.5(.........................................................................\
+........ 39)265.5 585.6 R 2.5(5.1.9. K)102 600 R 2.5<8a6b>2.5 G .3 -.15
+(ey \214)156.62 600 T(le declaration).15 E 23.5(..............................\
+................................................................ 39)4.88 F 2.5
+(5.2. Building)87 614.4 R 2.5(aC)2.5 G(on\214guration File From Scratch)158.12
+614.4 Q 23.5
+(......................................................................... 41)
+3.77 F 2.5(5.2.1. What)102 628.8 R(you are trying to do)2.5 E 23.5(...........\
+..............................................................................\
+.... 42)2.96 F 2.5(5.2.2. Philosoph)102 643.2 R 3.54(y.)-.05 G 23.5(..........\
+..............................................................................\
+........................... 42)180.5 643.2 R 2.5(5.2.2.1. Lar)117 657.6 R
+(ge site, man)-.18 E 2.5(yh)-.15 G(osts \212 minimum information)226.1 657.6 Q
+23.5(................................................ 42)2.72 F 2.5
+(5.2.2.2. Small)117 672 R(site \212 complete information)2.5 E 23.5
+(.................................................................... 43)4.89 F
+2.5(5.2.2.3. Single)117 686.4 R 1.27(host ....................................\
+.......................................................................)2.5 F
+(43)494 686.4 Q 2.5(5.2.2.4. A)117 700.8 R(completely dif)2.5 E
+(ferent philosoph)-.25 E 3.26(y.)-.05 G 23.5
+(..................................................................... 43)295.5
+700.8 R 2.5(5.2.3. Rele)102 715.2 R -.25(va)-.25 G(nt issues).25 E 23.5(......\
+..............................................................................\
+......................... 44)4.56 F EP
+%%Page: 5 63
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Sendmail Installation and Operation Guide)72 60 Q
+(SMM:08-5)457.9 60 Q/F1 10/Times-Roman@0 SF 2.5(5.2.4. Ho)102 96 R 2.5(wt)-.25
+G 2.5(op)153.97 96 S 2.38(roceed .............................................\
+...............................................................)166.47 96 R(44)
+494 96 Q 2.5(5.2.5. T)102 110.4 R(esting the re)-.7 E
+(writing rules \212 the \255bt \215ag)-.25 E 23.5
+(.................................................................... 44)2.99 F
+2.5(5.2.6. Building)102 124.8 R(mailer descriptions)2.5 E 23.5(...............\
+......................................................................... 45)
+4.61 F 2.5(5.3. The)87 139.2 R(User Database)2.5 E 23.5(......................\
+..............................................................................\
+............ 46)4.92 F 2.5(5.3.1. Structure)102 153.6 R(of the user database)
+2.5 E 23.5(...................................................................\
+.................... 47)2.7 F 2.5(5.3.2. User)102 168 R(database semantics)2.5
+E 23.5(.......................................................................\
+........................ 47)3.25 F 2.5(5.3.3. Creating)102 184.4 R
+(the database)2.5 E/F2 7/Times-Roman@0 SF(18)215.59 180.4 Q F1 23.5(..........\
+..............................................................................\
+......... 48)225.5 184.4 R 2.5(6. O)72 198.8 R(THER CONFIGURA)-.4 E 1.97(TION \
+..............................................................................\
+...........................)-1.11 F(48)494 198.8 Q 2.5(6.1. P)87 213.2 R
+(arameters in src/Mak)-.15 E 1.55(e\214le ....................................\
+................................................................)-.1 F(48)494
+213.2 Q 2.5(6.2. P)87 227.6 R(arameters in src/conf.h)-.15 E 23.5(............\
+..............................................................................\
+.............. 49)4.23 F 2.5(6.3. Con\214guration)87 242 R(in src/conf.c)2.5 E
+23.5(.........................................................................\
+........................... 51)3.51 F 2.5(6.3.1. Built-in)102 256.4 R
+(Header Semantics)2.5 E 23.5(.................................................\
+.......................................... 51)4.9 F 2.5(6.3.2. Restricting)102
+270.8 R(Use of Email)2.5 E 23.5(..............................................\
+................................................ 52)4.34 F 2.5(6.3.3. Load)102
+285.2 R -1.17 -.74(Av e)2.5 H(rage Computation).74 E 23.5(....................\
+...................................................................... 53)2.74
+F 2.5(6.3.4. Ne)102 299.6 R 2.5(wD)-.25 G(atabase Map Classes)157.85 299.6 Q
+23.5(.........................................................................\
+................ 53)4.89 F 2.5(6.3.5. Queueing)102 314 R 1.56(Function .......\
+..............................................................................\
+..................)2.5 F(53)494 314 Q 2.5(6.3.6. Refusing)102 328.4 R
+(Incoming SMTP Connections)2.5 E 23.5
+(....................................................................... 54)
+2.94 F 2.5(6.3.7. Load)102 342.8 R -1.17 -.74(Av e)2.5 H(rage Computation).74 E
+23.5(.........................................................................\
+................. 54)2.74 F 2.5(6.4. Con\214guration)87 357.2 R
+(in src/daemon.c)2.5 E 23.5(..................................................\
+............................................ 54)4.62 F 2.5(7. CHANGES)72 371.6
+R(IN VERSION 8)2.5 E 23.5(....................................................\
+...................................................... 54)4.9 F 2.5
+(7.1. Connection)87 386 R 1.56(Caching .......................................\
+.......................................................................)2.5 F
+(55)494 386 Q 2.5(7.2. MX)87 400.4 R 2.39(Piggybacking .......................\
+..............................................................................\
+............)2.5 F(55)494 400.4 Q 2.5(7.3. RFC)87 414.8 R(1123 Compliance)2.5 E
+23.5(.........................................................................\
+................................. 55)3.77 F 2.5(7.4. Extended)87 429.2 R
+(SMTP Support)2.5 E 23.5(.....................................................\
+.................................................. 55)2.94 F 2.5
+(7.5. Eight-Bit)87 443.6 R .44(Clean .........................................\
+.............................................................................)
+2.5 F(55)494 443.6 Q 2.5(7.6. User)87 458 R .47(Database .....................\
+..............................................................................\
+.....................)2.5 F(55)494 458 Q 2.5(7.7. Impro)87 472.4 R -.15(ve)-.15
+G 2.5(dB).15 G(IND Support)154.75 472.4 Q 23.5(...............................\
+........................................................................ 55)
+3.81 F 2.5(7.8. K)87 486.8 R -.15(ey)-.25 G(ed Files).15 E 23.5(..............\
+..............................................................................\
+................................ 56)3.35 F 2.5(7.9. Multi-W)87 501.2 R
+(ord Classes)-.8 E 23.5(......................................................\
+......................................................... 56)3.47 F 2.5
+(7.10. Deferred)87 515.6 R(Macro Expansion)2.5 E 23.5(........................\
+......................................................................... 56)
+4.65 F 2.5(7.11. IDENT)87 530 R(Protocol Support)2.5 E 23.5(..................\
+..............................................................................\
+..... 56)2.95 F 2.5(7.12. P)87 544.4 R(arsing Bug Fix)-.15 E .46(es ..........\
+..............................................................................\
+........................)-.15 F(56)494 544.4 Q 2.5(7.13. Separate)87 558.8 R
+(En)2.5 E -.15(ve)-.4 G(lope/Header Processing).15 E 23.5(....................\
+............................................................ 56)4.37 F 2.5
+(7.14. Owner)87 573.2 R(-List Propag)-.2 E(ates to En)-.05 E -.15(ve)-.4 G 1.27
+(lope ........................................................................\
+............).15 F(56)494 573.2 Q 2.5(7.15. Dynamic)87 587.6 R
+(Header Allocation)2.5 E 23.5(................................................\
+................................................ 56)3.25 F 2.5(7.16. Ne)87 602
+R 2.5(wC)-.25 G(ommand Line Flags)139.8 602 Q 23.5(...........................\
+....................................................................... 56)3.2
+F 2.5(7.17. Enhanced)87 616.4 R(Command Line Flags)2.5 E 23.5(................\
+......................................................................... 56)
+4.9 F 2.5(7.18. Ne)87 630.8 R 2.5(wa)-.25 G(nd Old Con\214guration Line T)
+137.57 630.8 Q .4(ypes .......................................................\
+.......................)-.8 F(57)494 630.8 Q 2.5(7.19. Ne)87 645.2 R 2.5(wO)
+-.25 G .7(ptions .............................................................\
+...........................................................)140.35 645.2 R(57)
+494 645.2 Q 2.5(7.20. Extended)87 659.6 R 1.56(Options .......................\
+..............................................................................\
+...........)2.5 F(57)494 659.6 Q 2.5(7.21. Ne)87 674 R 2.5(wM)-.25 G
+(ailer Flags)142.02 674 Q 23.5(...............................................\
+................................................................. 57)4.04 F 2.5
+(7.22. Ne)87 688.4 R 2.5(wP)-.25 G(re-De\214ned Macros)138.69 688.4 Q 23.5(...\
+..............................................................................\
+................... 58)4.06 F 2.5(7.23. Ne)87 702.8 R 2.5(wL)-.25 G(HS T)139.24
+702.8 Q(ok)-.8 E 1.33(en .....................................................\
+.............................................................)-.1 F(58)494
+702.8 Q 2.5(7.24. Bigger)87 717.2 R(Def)2.5 E(aults ..........................\
+..............................................................................\
+............)-.1 E(58)494 717.2 Q EP
+%%Page: 6 64
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF 198.36(SMM:08-6 Sendmail)72 60 R
+(Installation and Operation Guide)2.5 E/F1 10/Times-Roman@0 SF 2.5(7.25. Dif)87
+96 R(ferent Def)-.25 E(ault T)-.1 E(uning P)-.45 E 1.99(arameters ............\
+......................................................................)-.15 F
+(58)494 96 Q 2.5(7.26. Auto-Quoting)87 110.4 R(in Addresses)2.5 E 23.5(.......\
+..............................................................................\
+............ 58)3.51 F 2.5(7.27. Symbolic)87 124.8 R(Names On Error Mailer)2.5
+E 23.5(.......................................................................\
+............... 58)4.91 F 2.5(7.28. SMTP)87 139.2 R(VRFY Doesn')2.5 E 2.5(tE)
+-.18 G 1.18(xpand ............................................................\
+................................)209.88 139.2 R(58)494 139.2 Q 2.5(7.29. [IPC])
+87 153.6 R(Mailers Allo)2.5 E 2.5(wM)-.25 G(ultiple Hosts)205.91 153.6 Q 23.5(\
+..............................................................................\
+..... 58)3.75 F 2.5(7.30. Aliases)87 168 R 1.29(Extended .....................\
+..............................................................................\
+..............)2.5 F(59)494 168 Q 2.5(7.31. Portability)87 182.4 R
+(and Security Enhancements)2.5 E 23.5(........................................\
+....................................... 59)2.68 F 2.5(7.32. Miscellaneous)87
+196.8 R 1.29(Changes .........................................................\
+..............................................)2.5 F(59)494 196.8 Q 2.5(8. A)72
+211.2 R(CKNO)-.4 E .1(WLEDGEMENTS ............................................\
+................................................................)-.35 F(59)494
+211.2 Q(Appendix A.)72 225.6 Q(COMMAND LINE FLA)5 E 1.97(GS ..................\
+.......................................................................)-.4 F
+(60)494 225.6 Q(Appendix B.)72 240 Q -.1(QU)5 G(EUE FILE FORMA).1 E 1.38(TS ..\
+..............................................................................\
+............)-1.11 F(62)494 240 Q(Appendix C.)72 254.4 Q(SUMMAR)5 E 2.5(YO)-.65
+G 2.5(FS)188.85 254.4 S(UPPOR)202.47 254.4 Q 2.5(TF)-.6 G 1.12(ILES ..........\
+....................................................................)248.27
+254.4 R(64)494 254.4 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/usr.sbin/sendmail/doc/op/spell.ok b/usr.sbin/sendmail/doc/op/spell.ok
new file mode 100644
index 0000000..d1cb19e
--- /dev/null
+++ b/usr.sbin/sendmail/doc/op/spell.ok
@@ -0,0 +1,324 @@
+AA06698
+AA06703
+AA22757
+AA22777
+AA99999
+ACHECK
+ARPANET
+AVENRUN
+Allman
+Arpa
+Arpanet
+BSD
+BSD4.4
+BTree
+Bcc
+BitNET
+CHmonet
+CHucbmonet
+CNAME
+CS.Berkeley.EDU
+Cdaemon
+Ceric
+Cnt
+Ctest.cf
+DB
+DLA
+DdfAA13557
+Dj
+DlFrom
+DnMAILER
+Dq
+EDU
+EOH
+EXPN
+Eol
+Eowner
+Eric.Allman
+FAX
+FSCALE
+Fri
+GECOS
+Guide''SMM:07
+H?F?from
+H?P?return
+H?x?full
+HELO
+HTo
+HdrInfo
+HiTech.COM
+Hmessage
+Hreceived
+Hsubject
+INT
+IP
+IPC
+Jul
+Kmapname
+LAN
+LHS
+LOCKF
+Linelimit
+LocalMailer
+MATCHGECOS
+MAXATOM
+MAXHOP
+MAXLINE
+MAXMAILERS
+MAXMXHOSTS
+MAXNAME
+MAXPRIORITIES
+MAXPV
+MAXRWSETS
+MAXTRUST
+MAXUSERENVIRON
+MX
+Makefile
+Makefile.dist
+Maxsize
+Meta
+Mether
+Mlocal
+MsgSize
+NEWDB
+NIS
+NOOP
+NOTUNIX
+NoReturn
+OJ
+OSTYPE
+OT3d
+PSyserr
+Pfirst
+Pjunk
+Pspecial
+QUEUESIZE
+RCPT
+README
+RFC
+RFC's
+RFC1123
+RFC819
+RFC821
+RFC822
+RHS
+Rbostic
+Reric
+Ruleset
+Rulesets
+S,D
+SETPROCTITLE
+SITECONFIG
+SMM:07
+SMTP
+SUBR
+SYS5TZ
+SYSTEM5
+Seric
+TCP
+TSyserr
+UCBARPA
+UCBARPA:eric
+UGLYUUCP
+USERDB
+Ucbvax
+Ultrix3.0
+Usrerr
+VRFY
+Wildcard
+YP
+a.CC.Berkeley.EDU
+aliases.db
+aliases.dir
+aliases.pag
+args
+automounter
+av
+avenrun
+bd
+behaviour
+bi
+bollard
+bool
+bostic
+bp
+bt
+btree
+buf
+bufsize
+bz
+c70:user
+calder
+canonification
+checkcompat
+cnt
+conf.c
+conf.h
+contessa
+cs
+cs.exposed.m4
+cs.hidden.m4
+csam
+csam.arpa
+cw
+daemon.c
+db
+decvax
+default:mailname
+delivermail
+dev
+dir
+doc
+ef
+email
+eric
+eric:mailname
+ernie
+errno
+fallback
+fax
+fi
+filename
+filenames
+fo
+foo.bar.baz.de
+fullname
+gateway.HiTech.COM
+getla
+getloadavg
+groupid
+hdrinfo
+hname
+hoptoad
+host.domain
+hosta
+hostb
+htemplate
+ie
+iff
+int
+ip
+lbl
+lf
+lhs
+lib
+lnx
+localhost
+lockf
+lp
+mail.CS.Berkeley.EDU
+mail.cf
+maildrop
+mailname
+mailq
+mailstats
+mailstats.c
+makemap
+mammoth.Berkeley.EDU
+mammoth.Berkeley.EDU.HiTech.COM
+mapclass
+maphostname
+mapname
+matisse
+mc
+mckusick
+meC
+mflags
+monet
+monet:bollard
+mqueue
+msg
+name1
+name2
+nameserver
+newalias
+nkainc
+nosuchuser
+num
+oM
+oQ
+oT1d
+oT2m
+okeeffe.CS.Berkeley.EDU
+omqueue
+ostype
+pUUCP:uunet
+pag
+pag,dir
+pathname
+pathnames
+pathnames.h
+pid
+pp
+prep.ai.MIT.EDU
+prog
+q30m
+qf
+querytype
+queueups
+rc.local
+resolv.conf
+rfc819.lpr
+rfc822.lpr
+rhs
+rlsm
+ruleset
+rulesets
+rwset
+rwsets
+sam
+sbin
+sendmail.cf
+sendmail.cw
+sendmail.fc
+sendmail.hf
+sendmail.st
+setupmaps
+si
+site.config.file
+siteconfig
+smtp
+sp
+src
+suid
+syserr
+sysname
+tcpproto.mc
+test.cf
+text1
+text2
+tf
+timestamp
+timestamps
+ucb
+ucbarpa
+ucblib
+ucbmonet
+ucbvax
+ucbvax.mc
+udbspec
+user1
+user2
+usera
+userb
+userc
+userid
+username
+usrerr
+uucpproto.mc
+uunet
+val
+vangogh.CS.Berkeley.EDU
+vangogh.berkeley.edu
+var
+vikki
+voyeurism
+wildcard
+wildcards
+wnj
+word1
+word2
+xf
+xxx
+xyzvax
+yp
diff --git a/usr.sbin/sendmail/doc/rfc/rfc819.txt b/usr.sbin/sendmail/doc/rfc/rfc819.txt
new file mode 100644
index 0000000..d66f8d9
--- /dev/null
+++ b/usr.sbin/sendmail/doc/rfc/rfc819.txt
@@ -0,0 +1,1044 @@
+
+
+Network Working Group Zaw-Sing Su (SRI)
+Request for Comments: 819 Jon Postel (ISI)
+ August 1982
+
+
+
+ The Domain Naming Convention for Internet User Applications
+
+
+
+
+1. Introduction
+
+ For many years, the naming convention "<user>@<host>" has served the
+ ARPANET user community for its mail system, and the substring
+ "<host>" has been used for other applications such as file transfer
+ (FTP) and terminal access (Telnet). With the advent of network
+ interconnection, this naming convention needs to be generalized to
+ accommodate internetworking. A decision has recently been reached to
+ replace the simple name field, "<host>", by a composite name field,
+ "<domain>" [2]. This note is an attempt to clarify this generalized
+ naming convention, the Internet Naming Convention, and to explore the
+ implications of its adoption for Internet name service and user
+ applications.
+
+ The following example illustrates the changes in naming convention:
+
+ ARPANET Convention: Fred@ISIF
+ Internet Convention: Fred@F.ISI.ARPA
+
+ The intent is that the Internet names be used to form a
+ tree-structured administrative dependent, rather than a strictly
+ topology dependent, hierarchy. The left-to-right string of name
+ components proceeds from the most specific to the most general, that
+ is, the root of the tree, the administrative universe, is on the
+ right.
+
+ The name service for realizing the Internet naming convention is
+ assumed to be application independent. It is not a part of any
+ particular application, but rather an independent name service serves
+ different user applications.
+
+2. The Structural Model
+
+ The Internet naming convention is based on the domain concept. The
+ name of a domain consists of a concatenation of one or more <simple
+ names>. A domain can be considered as a region of jurisdiction for
+ name assignment and of responsibility for name-to-address
+ translation. The set of domains forms a hierarchy.
+
+ Using a graph theory representation, this hierarchy may be modeled as
+ a directed graph. A directed graph consists of a set of nodes and a
+
+
+Su & Postel [Page 1]
+
+
+
+RFC 819 August 1982;
+
+
+ collection of arcs, where arcs are identified by ordered pairs of
+ distinct nodes [1]. Each node of the graph represents a domain. An
+ ordered pair (B, A), an arc from B to A, indicates that B is a
+ subdomain of domain A, and B is a simple name unique within A. We
+ will refer to B as a child of A, and A a parent of B. The directed
+ graph that best describes the naming hierarchy is called an
+ "in-tree", which is a rooted tree with all arcs directed towards the
+ root (Figure 1). The root of the tree represents the naming universe,
+ ancestor of all domains. Endpoints (or leaves) of the tree are the
+ lowest-level domains.
+
+ U
+ / | \
+ / | \ U -- Naming Universe
+ ^ ^ ^ I -- Intermediate Domain
+ | | | E -- Endpoint Domain
+ I E I
+ / \ |
+ ^ ^ ^
+ | | |
+ E E I
+ / | \
+ ^ ^ ^
+ | | |
+ E E E
+
+ Figure 1
+ The In-Tree Model for Domain Hierarchy
+
+ The simple name of a child in this model is necessarily unique within
+ its parent domain. Since the simple name of the child's parent is
+ unique within the child's grandparent domain, the child can be
+ uniquely named in its grandparent domain by the concatenation of its
+ simple name followed by its parent's simple name.
+
+ For example, if the simple name of a child is "C1" then no other
+ child of the same parent may be named "C1". Further, if the
+ parent of this child is named "P1", then "P1" is a unique simple
+ name in the child's grandparent domain. Thus, the concatenation
+ C1.P1 is unique in C1's grandparent domain.
+
+ Similarly, each element of the hierarchy is uniquely named in the
+ universe by its complete name, the concatenation of its simple name
+ and those for the domains along the trail leading to the naming
+ universe.
+
+ The hierarchical structure of the Internet naming convention supports
+ decentralization of naming authority and distribution of name service
+ capability. We assume a naming authority and a name server
+
+
+Su & Postel [Page 2]
+
+
+
+RFC 819 August 1982;
+
+
+ associated with each domain. In Sections 5 and 6 respectively the
+ name service and the naming authority are discussed.
+
+ Within an endpoint domain, unique names are assigned to <user>
+ representing user mailboxes. User mailboxes may be viewed as
+ children of their respective domains.
+
+ In reality, anomalies may exist violating the in-tree model of naming
+ hierarchy. Overlapping domains imply multiple parentage, i.e., an
+ entity of the naming hierarchy being a child of more than one domain.
+ It is conceivable that ISI can be a member of the ARPA domain as well
+ as a member of the USC domain (Figure 2). Such a relation
+ constitutes an anomaly to the rule of one-connectivity between any
+ two points of a tree. The common child and the sub-tree below it
+ become descendants of both parent domains.
+
+ U
+ / | \
+ / . \
+ . . ARPA
+ . . | \
+ USC | \
+ \ | .
+ \ | .
+ ISI
+
+ Figure 2
+ Anomaly in the In-Tree Model
+
+ Some issues resulting from multiple parentage are addressed in
+ Appendix B. The general implications of multiple parentage are a
+ subject for further investigation.
+
+3. Advantage of Absolute Naming
+
+ Absolute naming implies that the (complete) names are assigned with
+ respect to a universal reference point. The advantage of absolute
+ naming is that a name thus assigned can be universally interpreted
+ with respect to the universal reference point. The Internet naming
+ convention provides absolute naming with the naming universe as its
+ universal reference point.
+
+ For relative naming, an entity is named depending upon the position
+ of the naming entity relative to that of the named entity. A set of
+ hosts running the "unix" operating system exchange mail using a
+ method called "uucp". The naming convention employed by uucp is an
+ example of relative naming. The mail recipient is typically named by
+ a source route identifying a chain of locally known hosts linking the
+
+
+
+Su & Postel [Page 3]
+
+
+
+RFC 819 August 1982;
+
+
+ sender's host to the recipient's. A destination name can be, for
+ example,
+
+ "alpha!beta!gamma!john",
+
+ where "alpha" is presumably known to the originating host, "beta" is
+ known to "alpha", and so on.
+
+ The uucp mail system has demonstrated many of the problems inherent
+ to relative naming. When the host names are only locally
+ interpretable, routing optimization becomes impossible. A reply
+ message may have to traverse the reverse route to the original sender
+ in order to be forwarded to other parties.
+
+ Furthermore, if a message is forwarded by one of the original
+ recipients or passed on as the text of another message, the frame of
+ reference of the relative source route can be completely lost. Such
+ relative naming schemes have severe problems for many of the uses
+ that we depend upon in the ARPA Internet community.
+
+4. Interoperability
+
+ To allow interoperation with a different naming convention, the names
+ assigned by a foreign naming convention need to be accommodated.
+ Given the autonomous nature of domains, a foreign naming environment
+ may be incorporated as a domain anywhere in the hierarchy. Within
+ the naming universe, the name service for a domain is provided within
+ that domain. Thus, a foreign naming convention can be independent of
+ the Internet naming convention. What is implied here is that no
+ standard convention for naming needs to be imposed to allow
+ interoperations among heterogeneous naming environments.
+
+ For example:
+
+ There might be a naming convention, say, in the FOO world,
+ something like "<user>%<host>%<area>". Communications with an
+ entity in that environment can be achieved from the Internet
+ community by simply appending ".FOO" on the end of the name in
+ that foreign convention.
+
+ John%ISI-Tops20-7%California.FOO
+
+ Another example:
+
+ One way of accommodating the "uucp world" described in the last
+ section is to declare it as a foreign system. Thus, a uucp
+ name
+
+ "alpha!beta!gamma!john"
+
+
+Su & Postel [Page 4]
+
+
+
+RFC 819 August 1982;
+
+
+ might be known in the Internet community as
+
+ "alpha!beta!gamma!john.UUCP".
+
+ Communicating with a complex subdomain is another case which can
+ be treated as interoperation. A complex subdomain is a domain
+ with complex internal naming structure presumably unknown to the
+ outside world (or the outside world does not care to be concerned
+ with its complexity).
+
+ For the mail system application, the names embedded in the message
+ text are often used by the destination for such purpose as to reply
+ to the original message. Thus, the embedded names may need to be
+ converted for the benefit of the name server in the destination
+ environment.
+
+ Conversion of names on the boundary between heterogeneous naming
+ environments is a complex subject. The following example illustrates
+ some of the involved issues.
+
+ For example:
+
+ A message is sent from the Internet community to the FOO
+ environment. It may bear the "From" and "To" fields as:
+
+ From: Fred@F.ISI.ARPA
+ To: John%ISI-Tops20-7%California.FOO
+
+ where "FOO" is a domain independent of the Internet naming
+ environment. The interface on the boundary of the two
+ environments may be represented by a software module. We may
+ assume this interface to be an entity of the Internet community
+ as well as an entity of the FOO community. For the benefit of
+ the FOO environment, the "From" and "To" fields need to be
+ modified upon the message's arrival at the boundary. One may
+ view naming as a separate layer of protocol, and treat
+ conversion as a protocol translation. The matter is
+ complicated when the message is sent to more than one
+ destination within different naming environments; or the
+ message is destined within an environment not sharing boundary
+ with the originating naming environment.
+
+ While the general subject concerning conversion is beyond the scope
+ of this note, a few questions are raised in Appendix D.
+
+
+
+
+
+
+
+Su & Postel [Page 5]
+
+
+
+RFC 819 August 1982;
+
+
+5. Name Service
+
+ Name service is a network service providing name-to-address
+ translation. Such service may be achieved in a number of ways. For
+ a simple networking environment, it can be accomplished with a single
+ central database containing name-to-address correspondence for all
+ the pertinent network entities, such as hosts.
+
+ In the case of the old ARPANET host names, a central database is
+ duplicated in each individual host. The originating module of an
+ application process would query the local name service (e.g., make a
+ system call) to obtain network address for the destination host. With
+ the proliferation of networks and an accelerating increase in the
+ number of hosts participating in networking, the ever growing size,
+ update frequency, and the dissemination of the central database makes
+ this approach unmanageable.
+
+ The hierarchical structure of the Internet naming convention supports
+ decentralization of naming authority and distribution of name service
+ capability. It readily accommodates growth of the naming universe.
+ It allows an arbitrary number of hierarchical layers. The addition
+ of a new domain adds little complexity to an existing Internet
+ system.
+
+ The name service at each domain is assumed to be provided by one or
+ more name servers. There are two models for how a name server
+ completes its work, these might be called "iterative" and
+ "recursive".
+
+ For an iterative name server there may be two kinds of responses.
+ The first kind of response is a destination address. The second
+ kind of response is the address of another name server. If the
+ response is a destination address, then the query is satisfied. If
+ the response is the address of another name server, then the query
+ must be repeated using that name server, and so on until a
+ destination address is obtained.
+
+ For a recursive name server there is only one kind of response --
+ a destination address. This puts an obligation on the name server
+ to actually make the call on another name server if it can't
+ answer the query itself.
+
+ It is noted that looping can be avoided since the names presented for
+ translation can only be of finite concatenation. However, care
+ should be taken in employing mechanisms such as a pointer to the next
+ simple name for resolution.
+
+ We believe that some name servers will be recursive, but we don't
+ believe that all will be. This means that the caller must be
+
+
+Su & Postel [Page 6]
+
+
+
+RFC 819 August 1982;
+
+
+ prepared for either type of server. Further discussion and examples
+ of name service is given in Appendix C.
+
+ The basic name service at each domain is the translation of simple
+ names to addresses for all of its children. However, if only this
+ basic name service is provided, the use of complete (or fully
+ qualified) names would be required. Such requirement can be
+ unreasonable in practice. Thus, we propose the use of partial names
+ in the context in which their uniqueness is preserved. By
+ construction, naming uniqueness is preserved within the domain of a
+ common ancestry. Thus, a partially qualified name is constructed by
+ omitting from the complete name ancestors common to the communicating
+ parties. When a partially qualified name leaves its context of
+ uniqueness it must be additionally qualified.
+
+ The use of partially qualified names places a requirement on the
+ Internet name service. To satisfy this requirement, the name service
+ at each domain must be capable of, in addition to the basic service,
+ resolving simple names for all of its ancestors (including itself)
+ and their children. In Appendix B, the required distinction among
+ simple names for such resolution is addressed.
+
+6. Naming Authority
+
+ Associated with each domain there must be a naming authority to
+ assign simple names and ensure proper distinction among simple names.
+
+ Note that if the use of partially qualified names is allowed in a
+ sub-domain, the uniqueness of simple names inside that sub-domain is
+ insufficient to avoid ambiguity with names outside the subdomain.
+ Appendix B discusses simple name assignment in a sub-domain that
+ would allow the use of partially qualified names without ambiguity.
+
+ Administratively, associated with each domain there is a single
+ person (or office) called the registrar. The registrar of the naming
+ universe specifies the top-level set of domains and designates a
+ registrar for each of these domains. The registrar for any given
+ domain maintains the naming authority for that domain.
+
+7. Network-Oriented Applications
+
+ For user applications such as file transfer and terminal access, the
+ remote host needs to be named. To be compatible with ARPANET naming
+ convention, a host can be treated as an endpoint domain.
+
+ Many operating systems or programming language run-time environments
+ provide functions or calls (JSYSs, SVCs, UUOs, SYSs, etc.) for
+ standard services (e.g., time-of-day, account-of-logged-in-user,
+ convert-number-to-string). It is likely to be very helpful if such a
+
+
+Su & Postel [Page 7]
+
+
+
+RFC 819 August 1982;
+
+
+ function or call is developed for translating a host name to an
+ address. Indeed, several systems on the ARPANET already have such
+ facilities for translating an ARPANET host name into an ARPANET
+ address based on internal tables.
+
+ We recommend that this provision of a standard function or call for
+ translating names to addresses be extended to accept names of
+ Internet convention. This will promote a consistent interface to the
+ users of programs involving internetwork activities. The standard
+ facility for translating Internet names to Internet addresses should
+ include all the mechanisms available on the host, such as checking a
+ local table or cache of recently checked names, or consulting a name
+ server via the Internet.
+
+8. Mail Relaying
+
+ Relaying is a feature adopted by more and more mail systems.
+ Relaying facilitates, among other things, interoperations between
+ heterogeneous mail systems. The term "relay" is used to describe the
+ situation where a message is routed via one or more intermediate
+ points between the sender and the recipient. The mail relays are
+ normally specified explicitly as relay points in the instructions for
+ message delivery. Usually, each of the intermediate relays assume
+ responsibility for the relayed message [3].
+
+ A point should be made on the basic difference between mail
+ relaying and the uucp naming system. The difference is that
+ although mail relaying with absolute naming can also be considered
+ as a form of source routing, the names of each intermediate points
+ and that of the destination are universally interpretable, while
+ the host names along a source route of the uucp convention is
+ relative and thus only locally interpretable.
+
+ The Internet naming convention explicitly allows interoperations
+ among heterogeneous systems. This implies that the originator of a
+ communication may name a destination which resides in a foreign
+ system. The probability is that the destination network address may
+ not be comprehensible to the transport system of the originator.
+ Thus, an implicit relaying mechanism is called for at the boundary
+ between the domains. The function of this implicit relay is the same
+ as the explicit relay.
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 8]
+
+
+
+RFC 819 August 1982;
+
+
+9. Implementation
+
+ The Actual Domains
+
+ The initial set of top-level names include:
+
+ ARPA
+
+ This represents the set of organizations involved in the
+ Internet system through the authority of the U.S. Defense
+ Advanced Research Projects Agency. This includes all the
+ research and development hosts on the ARPANET and hosts on
+ many other nets as well. But note very carefully that the
+ top-level domain "ARPA" does not map one-to-one with the
+ ARPANET -- domains are administrative, not topological.
+
+ Transition
+
+ In the transition from the ARPANET naming convention to the
+ Internet naming convention, a host name may be used as a simple
+ name for an endpoint domain. Thus, if "USC-ISIF" is an ARPANET
+ host name, then "USC-ISIF.ARPA" is the name of an Internet domain.
+
+10. Summary
+
+ A hierarchical naming convention based on the domain concept has been
+ adopted by the Internet community. It is an absolute naming
+ convention defined along administrative rather than topological
+ boundaries. This naming convention is adaptive for interoperations
+ with other naming conventions. Thus, no standard convention needs to
+ be imposed for interoperations among heterogeneous naming
+ environments.
+
+ This Internet naming convention allows distributed name service and
+ naming authority functions at each domain. We have specified these
+ functions required at each domain. Also discussed are implications
+ on network-oriented applications, mail systems, and administrative
+ aspects of this convention.
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 9]
+
+
+
+RFC 819 August 1982;
+
+
+APPENDIX A
+
+ The BNF Specification
+
+ We present here a rather detailed "BNF" definition of the allowed
+ form for a computer mail "mailbox" composed of a "local-part" and a
+ "domain" (separated by an at sign). Clearly, the domain can be used
+ separately in other network-oriented applications.
+
+ <mailbox> ::= <local-part> "@" <domain>
+
+ <local-part> ::= <string> | <quoted-string>
+
+ <string> ::= <char> | <char> <string>
+
+ <quoted-string> ::= """ <qtext> """
+
+ <qtext> ::= "\" <x> | "\" <x> <qtext> | <q> | <q> <qtext>
+
+ <char> ::= <c> | "\" <x>
+
+ <domain> ::= <naming-domain> | <naming-domain> "." <domain>
+
+ <naming-domain> ::= <simple-name> | <address>
+
+ <simple-name> ::= <a> <ldh-str> <let-dig>
+
+ <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+ <let-dig> ::= <a> | <d>
+
+ <let-dig-hyp> ::= <a> | <d> | "-"
+
+ <address> :: = "#" <number> | "[" <dotnum> "]"
+
+ <number> ::= <d> | <d> <number>
+
+ <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
+
+ <snum> ::= one, two, or three digits representing a decimal integer
+ value in the range 0 through 255
+
+ <a> ::= any one of the 52 alphabetic characters A through Z in upper
+ case and a through z in lower case
+
+ <c> ::= any one of the 128 ASCII characters except <s> or <SP>
+
+ <d> ::= any one of the ten digits 0 through 9
+
+
+
+Su & Postel [Page 10]
+
+
+
+RFC 819 August 1982;
+
+
+ <q> ::= any one of the 128 ASCII characters except CR, LF, quote ("),
+ or backslash (\)
+
+ <x> ::= any one of the 128 ASCII characters (no exceptions)
+
+ <s> ::= "<", ">", "(", ")", "[", "]", "\", ".", ",", ";", ":", "@",
+ """, and the control characters (ASCII codes 0 through 31 inclusive
+ and 127)
+
+ Note that the backslash, "\", is a quote character, which is used to
+ indicate that the next character is to be used literally (instead of
+ its normal interpretation). For example, "Joe\,Smith" could be used
+ to indicate a single nine character user field with comma being the
+ fourth character of the field.
+
+ The simple names that make up a domain may contain both upper and
+ lower case letters (as well as digits and hyphen), but these names
+ are not case sensitive.
+
+ Hosts are generally known by names. Sometimes a host is not known to
+ the translation function and communication is blocked. To bypass
+ this barrier two forms of addresses are also allowed for host
+ "names". One form is a decimal integer prefixed by a pound sign, "#".
+ Another form, called "dotted decimal", is four small decimal integers
+ separated by dots and enclosed by brackets, e.g., "[123.255.37.2]",
+ which indicates a 32-bit ARPA Internet Address in four 8-bit fields.
+ (Of course, these numeric address forms are specific to the Internet,
+ other forms may have to be provided if this problem arises in other
+ transport systems.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 11]
+
+
+
+RFC 819 August 1982;
+
+
+APPENDIX B
+
+ An Aside on the Assignment of Simple Names
+
+ In the following example, there are two naming hierarchies joining at
+ the naming universe 'U'. One consists of domains (S, R, N, J, P, Q,
+ B, A); and the other (L, E, F, G, H, D, C, K, B, A). Domain B is
+ assumed to have multiple parentage as shown.
+
+ U
+ / \
+ / \
+ J L
+ / \
+ N E
+ / \ / \
+ R P D F
+ / \ | \ \
+ S Q C (X) G
+ \ / \ \
+ B K H
+ /
+ A
+
+ Figure 3
+ Illustration of Requirements for the Distinction of Simple Names
+
+ Suppose someone at A tries to initiate communication with destination
+ H. The fully qualified destination name would be
+
+ H.G.F.E.L.U
+
+ Omitting common ancestors, the partially qualified name for the
+ destination would be
+
+ H.G.F
+
+ To permit the case of partially qualified names, name server at A
+ needs to resolve the simple name F, i.e., F needs to be distinct from
+ all the other simple names in its database.
+
+ To enable the name server of a domain to resolve simple names, a
+ simple name for a child needs to be assigned distinct from those of
+ all of its ancestors and their immediate children. However, such
+ distinction would not be sufficient to allow simple name resolution
+ at lower-level domains because lower-level domains could have
+ multiple parentage below the level of this domain.
+
+ In the example above, let us assume that a name is to be assigned
+
+
+Su & Postel [Page 12]
+
+
+
+RFC 819 August 1982;
+
+
+ to a new domain X by D. To allow name server at D to resolve
+ simple names, the name for X must be distinct from L, E, D, C, F,
+ and J. However, allowing A to resolve simple names, X needs to be
+ also distinct from A, B, K, as well as from Q, P, N, and R.
+
+ The following observations can be made.
+
+ Simple names along parallel trails (distinct trails leading from
+ one domain to the naming universe) must be distinct, e.g., N must
+ be distinct from E for B or A to properly resolve simple names.
+
+ No universal uniqueness of simple names is called for, e.g., the
+ simple name S does not have to be distinct from that of E, F, G,
+ H, D, C, K, Q, B, or A.
+
+ The lower the level at which a domain occurs, the more immune it
+ is to the requirement of naming uniqueness.
+
+ To satisfy the required distinction of simple names for proper
+ resolution at all levels, a naming authority needs to ensure the
+ simple name to be assigned distinct from those in the name server
+ databases at the endpoint naming domains within its domain. As an
+ example, for D to assign a simple name for X, it would need to
+ consult databases at A and K. It is, however, acceptable to have
+ simple names under domain A identical with those under K. Failure of
+ such distinct assignment of simple names by naming authority of one
+ domain would jeopardize the capability of simple name resolution for
+ entities within the subtree under that domain.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 13]
+
+
+
+RFC 819 August 1982;
+
+
+APPENDIX C
+
+ Further Discussion of Name Service and Name Servers
+
+ The name service on a system should appear to the programmer of an
+ application program simply as a system call or library subroutine.
+ Within that call or subroutine there may be several types of methods
+ for resolving the name string into an address.
+
+ First, a local table may be consulted. This table may be a
+ complete table and may be updated frequently, or it may simply be
+ a cache of the few latest name to address mappings recently
+ determined.
+
+ Second, a call may be made to a name server to resolve the string
+ into a destination address.
+
+ Third, a call may be made to a name server to resolve the string
+ into a relay address.
+
+ Whenever a name server is called it may be a recursive server or an
+ interactive server.
+
+ If the server is recursive, the caller won't be able to tell if
+ the server itself had the information to resolve the query or
+ called another server recursively (except perhaps for the time it
+ takes).
+
+ If the server is iterative, the caller must be prepared for either
+ the answer to its query, or a response indicating that it should
+ call on a different server.
+
+ It should be noted that the main name service discussed in this memo
+ is simply a name string to address service. For some applications
+ there may be other services needed.
+
+ For example, even within the Internet there are several procedures
+ or protocols for actually transferring mail. One need is to
+ determine which mail procedures a destination host can use.
+ Another need is to determine the name of a relay host if the
+ source and destination hosts do not have a common mail procedure.
+ These more specialized services must be specific to each
+ application since the answers may be application dependent, but
+ the basic name to address translation is application independent.
+
+
+
+
+
+
+
+Su & Postel [Page 14]
+
+
+
+RFC 819 August 1982;
+
+
+APPENDIX D
+
+ Further Discussion of Interoperability and Protocol Translations
+
+ The translation of protocols from one system to another is often
+ quite difficult. Following are some questions that stem from
+ considering the translations of addresses between mail systems:
+
+ What is the impact of different addressing environments (i.e.,
+ environments of different address formats)?
+
+ It is noted that the boundary of naming environment may or may not
+ coincide with the boundary of different mail systems. Should the
+ conversion of naming be independent of the application system?
+
+ The boundary between different addressing environments may or may
+ not coincide with that of different naming environments or
+ application systems. Some generic approach appears to be
+ necessary.
+
+ If the conversion of naming is to be independent of the
+ application system, some form of interaction appears necessary
+ between the interface module of naming conversion with some
+ application level functions, such as the parsing and modification
+ of message text.
+
+ To accommodate encryption, conversion may not be desirable at all.
+ What then can be an alternative to conversion?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 15]
+
+
+
+RFC 819 August 1982;
+
+
+GLOSSARY
+
+ address
+
+ An address is a numerical identifier for the topological location
+ of the named entity.
+
+ name
+
+ A name is an alphanumeric identifier associated with the named
+ entity. For unique identification, a name needs to be unique in
+ the context in which the name is used. A name can be mapped to an
+ address.
+
+ complete (fully qualified) name
+
+ A complete name is a concatenation of simple names representing
+ the hierarchical relation of the named with respect to the naming
+ universe, that is it is the concatenation of the simple names of
+ the domain structure tree nodes starting with its own name and
+ ending with the top level node name. It is a unique name in the
+ naming universe.
+
+ partially qualified name
+
+ A partially qualified name is an abbreviation of the complete name
+ omitting simple names of the common ancestors of the communicating
+ parties.
+
+ simple name
+
+ A simple name is an alphanumeric identifier unique only within its
+ parent domain.
+
+ domain
+
+ A domain defines a region of jurisdiction for name assignment and
+ of responsibility for name-to-address translation.
+
+ naming universe
+
+ Naming universe is the ancestor of all network entities.
+
+ naming environment
+
+ A networking environment employing a specific naming convention.
+
+
+
+
+
+Su & Postel [Page 16]
+
+
+
+RFC 819 August 1982;
+
+
+ name service
+
+ Name service is a network service for name-to-address mapping.
+
+ name server
+
+ A name server is a network mechanism (e.g., a process) realizing
+ the function of name service.
+
+ naming authority
+
+ Naming authority is an administrative entity having the authority
+ for assigning simple names and responsibility for resolving naming
+ conflict.
+
+ parallel relations
+
+ A network entity may have one or more hierarchical relations with
+ respect to the naming universe. Such multiple relations are
+ parallel relations to each other.
+
+ multiple parentage
+
+ A network entity has multiple parentage when it is assigned a
+ simple name by more than one naming domain.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 17]
+
+
+
+RFC 819 August 1982;
+
+
+REFERENCES
+
+ [1] F. Harary, "Graph Theory", Addison-Wesley, Reading,
+ Massachusetts, 1969.
+
+ [2] J. Postel, "Computer Mail Meeting Notes", RFC-805,
+ USC/Information Sciences Institute, 8 February 1982.
+
+ [3] J. Postel, "Simple Mail Transfer Protocol", RFC-821,
+ USC/Information Sciences Institute, August 1982.
+
+ [4] D. Crocker, "Standard for the Format of ARPA Internet Text
+ Messages", RFC-822, Department of Electrical Engineering, University
+ of Delaware, August 1982.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Su & Postel [Page 18]
+
diff --git a/usr.sbin/sendmail/doc/rfc/rfc821.txt b/usr.sbin/sendmail/doc/rfc/rfc821.txt
new file mode 100644
index 0000000..d877b72
--- /dev/null
+++ b/usr.sbin/sendmail/doc/rfc/rfc821.txt
@@ -0,0 +1,4050 @@
+
+
+
+ RFC 821
+
+
+
+
+
+ SIMPLE MAIL TRANSFER PROTOCOL
+
+
+
+ Jonathan B. Postel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 1982
+
+
+
+ Information Sciences Institute
+ University of Southern California
+ 4676 Admiralty Way
+ Marina del Rey, California 90291
+
+ (213) 822-1511
+
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ TABLE OF CONTENTS
+
+ 1. INTRODUCTION .................................................. 1
+
+ 2. THE SMTP MODEL ................................................ 2
+
+ 3. THE SMTP PROCEDURE ............................................ 4
+
+ 3.1. Mail ..................................................... 4
+ 3.2. Forwarding ............................................... 7
+ 3.3. Verifying and Expanding .................................. 8
+ 3.4. Sending and Mailing ..................................... 11
+ 3.5. Opening and Closing ..................................... 13
+ 3.6. Relaying ................................................ 14
+ 3.7. Domains ................................................. 17
+ 3.8. Changing Roles .......................................... 18
+
+ 4. THE SMTP SPECIFICATIONS ...................................... 19
+
+ 4.1. SMTP Commands ........................................... 19
+ 4.1.1. Command Semantics ..................................... 19
+ 4.1.2. Command Syntax ........................................ 27
+ 4.2. SMTP Replies ............................................ 34
+ 4.2.1. Reply Codes by Function Group ......................... 35
+ 4.2.2. Reply Codes in Numeric Order .......................... 36
+ 4.3. Sequencing of Commands and Replies ...................... 37
+ 4.4. State Diagrams .......................................... 39
+ 4.5. Details ................................................. 41
+ 4.5.1. Minimum Implementation ................................ 41
+ 4.5.2. Transparency .......................................... 41
+ 4.5.3. Sizes ................................................. 42
+
+ APPENDIX A: TCP ................................................. 44
+ APPENDIX B: NCP ................................................. 45
+ APPENDIX C: NITS ................................................ 46
+ APPENDIX D: X.25 ................................................ 47
+ APPENDIX E: Theory of Reply Codes ............................... 48
+ APPENDIX F: Scenarios ........................................... 51
+
+ GLOSSARY ......................................................... 64
+
+ REFERENCES ....................................................... 67
+
+
+
+
+Network Working Group J. Postel
+Request for Comments: DRAFT ISI
+Replaces: RFC 788, 780, 772 August 1982
+
+ SIMPLE MAIL TRANSFER PROTOCOL
+
+
+1. INTRODUCTION
+
+ The objective of Simple Mail Transfer Protocol (SMTP) is to transfer
+ mail reliably and efficiently.
+
+ SMTP is independent of the particular transmission subsystem and
+ requires only a reliable ordered data stream channel. Appendices A,
+ B, C, and D describe the use of SMTP with various transport services.
+ A Glossary provides the definitions of terms as used in this
+ document.
+
+ An important feature of SMTP is its capability to relay mail across
+ transport service environments. A transport service provides an
+ interprocess communication environment (IPCE). An IPCE may cover one
+ network, several networks, or a subset of a network. It is important
+ to realize that transport systems (or IPCEs) are not one-to-one with
+ networks. A process can communicate directly with another process
+ through any mutually known IPCE. Mail is an application or use of
+ interprocess communication. Mail can be communicated between
+ processes in different IPCEs by relaying through a process connected
+ to two (or more) IPCEs. More specifically, mail can be relayed
+ between hosts on different transport systems by a host on both
+ transport systems.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 1]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+2. THE SMTP MODEL
+
+ The SMTP design is based on the following model of communication: as
+ the result of a user mail request, the sender-SMTP establishes a
+ two-way transmission channel to a receiver-SMTP. The receiver-SMTP
+ may be either the ultimate destination or an intermediate. SMTP
+ commands are generated by the sender-SMTP and sent to the
+ receiver-SMTP. SMTP replies are sent from the receiver-SMTP to the
+ sender-SMTP in response to the commands.
+
+ Once the transmission channel is established, the SMTP-sender sends a
+ MAIL command indicating the sender of the mail. If the SMTP-receiver
+ can accept mail it responds with an OK reply. The SMTP-sender then
+ sends a RCPT command identifying a recipient of the mail. If the
+ SMTP-receiver can accept mail for that recipient it responds with an
+ OK reply; if not, it responds with a reply rejecting that recipient
+ (but not the whole mail transaction). The SMTP-sender and
+ SMTP-receiver may negotiate several recipients. When the recipients
+ have been negotiated the SMTP-sender sends the mail data, terminating
+ with a special sequence. If the SMTP-receiver successfully processes
+ the mail data it responds with an OK reply. The dialog is purposely
+ lock-step, one-at-a-time.
+
+ -------------------------------------------------------------
+
+
+ +----------+ +----------+
+ +------+ | | | |
+ | User |<-->| | SMTP | |
+ +------+ | Sender- |Commands/Replies| Receiver-|
+ +------+ | SMTP |<-------------->| SMTP | +------+
+ | File |<-->| | and Mail | |<-->| File |
+ |System| | | | | |System|
+ +------+ +----------+ +----------+ +------+
+
+
+ Sender-SMTP Receiver-SMTP
+
+ Model for SMTP Use
+
+ Figure 1
+
+ -------------------------------------------------------------
+
+ The SMTP provides mechanisms for the transmission of mail; directly
+ from the sending user's host to the receiving user's host when the
+
+
+
+[Page 2] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ two host are connected to the same transport service, or via one or
+ more relay SMTP-servers when the source and destination hosts are not
+ connected to the same transport service.
+
+ To be able to provide the relay capability the SMTP-server must be
+ supplied with the name of the ultimate destination host as well as
+ the destination mailbox name.
+
+ The argument to the MAIL command is a reverse-path, which specifies
+ who the mail is from. The argument to the RCPT command is a
+ forward-path, which specifies who the mail is to. The forward-path
+ is a source route, while the reverse-path is a return route (which
+ may be used to return a message to the sender when an error occurs
+ with a relayed message).
+
+ When the same message is sent to multiple recipients the SMTP
+ encourages the transmission of only one copy of the data for all the
+ recipients at the same destination host.
+
+ The mail commands and replies have a rigid syntax. Replies also have
+ a numeric code. In the following, examples appear which use actual
+ commands and replies. The complete lists of commands and replies
+ appears in Section 4 on specifications.
+
+ Commands and replies are not case sensitive. That is, a command or
+ reply word may be upper case, lower case, or any mixture of upper and
+ lower case. Note that this is not true of mailbox user names. For
+ some hosts the user name is case sensitive, and SMTP implementations
+ must take case to preserve the case of user names as they appear in
+ mailbox arguments. Host names are not case sensitive.
+
+ Commands and replies are composed of characters from the ASCII
+ character set [1]. When the transport service provides an 8-bit byte
+ (octet) transmission channel, each 7-bit character is transmitted
+ right justified in an octet with the high order bit cleared to zero.
+
+ When specifying the general form of a command or reply, an argument
+ (or special symbol) will be denoted by a meta-linguistic variable (or
+ constant), for example, "<string>" or "<reverse-path>". Here the
+ angle brackets indicate these are meta-linguistic variables.
+ However, some arguments use the angle brackets literally. For
+ example, an actual reverse-path is enclosed in angle brackets, i.e.,
+ "<John.Smith@USC-ISI.ARPA>" is an instance of <reverse-path> (the
+ angle brackets are actually transmitted in the command or reply).
+
+
+
+
+
+Postel [Page 3]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+3. THE SMTP PROCEDURES
+
+ This section presents the procedures used in SMTP in several parts.
+ First comes the basic mail procedure defined as a mail transaction.
+ Following this are descriptions of forwarding mail, verifying mailbox
+ names and expanding mailing lists, sending to terminals instead of or
+ in combination with mailboxes, and the opening and closing exchanges.
+ At the end of this section are comments on relaying, a note on mail
+ domains, and a discussion of changing roles. Throughout this section
+ are examples of partial command and reply sequences, several complete
+ scenarios are presented in Appendix F.
+
+ 3.1. MAIL
+
+ There are three steps to SMTP mail transactions. The transaction
+ is started with a MAIL command which gives the sender
+ identification. A series of one or more RCPT commands follows
+ giving the receiver information. Then a DATA command gives the
+ mail data. And finally, the end of mail data indicator confirms
+ the transaction.
+
+ The first step in the procedure is the MAIL command. The
+ <reverse-path> contains the source mailbox.
+
+ MAIL <SP> FROM:<reverse-path> <CRLF>
+
+ This command tells the SMTP-receiver that a new mail
+ transaction is starting and to reset all its state tables and
+ buffers, including any recipients or mail data. It gives the
+ reverse-path which can be used to report errors. If accepted,
+ the receiver-SMTP returns a 250 OK reply.
+
+ The <reverse-path> can contain more than just a mailbox. The
+ <reverse-path> is a reverse source routing list of hosts and
+ source mailbox. The first host in the <reverse-path> should be
+ the host sending this command.
+
+ The second step in the procedure is the RCPT command.
+
+ RCPT <SP> TO:<forward-path> <CRLF>
+
+ This command gives a forward-path identifying one recipient.
+ If accepted, the receiver-SMTP returns a 250 OK reply, and
+ stores the forward-path. If the recipient is unknown the
+ receiver-SMTP returns a 550 Failure reply. This second step of
+ the procedure can be repeated any number of times.
+
+
+
+[Page 4] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ The <forward-path> can contain more than just a mailbox. The
+ <forward-path> is a source routing list of hosts and the
+ destination mailbox. The first host in the <forward-path>
+ should be the host receiving this command.
+
+ The third step in the procedure is the DATA command.
+
+ DATA <CRLF>
+
+ If accepted, the receiver-SMTP returns a 354 Intermediate reply
+ and considers all succeeding lines to be the message text.
+ When the end of text is received and stored the SMTP-receiver
+ sends a 250 OK reply.
+
+ Since the mail data is sent on the transmission channel the end
+ of the mail data must be indicated so that the command and
+ reply dialog can be resumed. SMTP indicates the end of the
+ mail data by sending a line containing only a period. A
+ transparency procedure is used to prevent this from interfering
+ with the user's text (see Section 4.5.2).
+
+ Please note that the mail data includes the memo header
+ items such as Date, Subject, To, Cc, From [2].
+
+ The end of mail data indicator also confirms the mail
+ transaction and tells the receiver-SMTP to now process the
+ stored recipients and mail data. If accepted, the
+ receiver-SMTP returns a 250 OK reply. The DATA command should
+ fail only if the mail transaction was incomplete (for example,
+ no recipients), or if resources are not available.
+
+ The above procedure is an example of a mail transaction. These
+ commands must be used only in the order discussed above.
+ Example 1 (below) illustrates the use of these commands in a mail
+ transaction.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 5]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of the SMTP Procedure
+
+ This SMTP example shows mail sent by Smith at host Alpha.ARPA,
+ to Jones, Green, and Brown at host Beta.ARPA. Here we assume
+ that host Alpha contacts host Beta directly.
+
+ S: MAIL FROM:<Smith@Alpha.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Jones@Beta.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Green@Beta.ARPA>
+ R: 550 No such user here
+
+ S: RCPT TO:<Brown@Beta.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: <CRLF>.<CRLF>
+ R: 250 OK
+
+ The mail has now been accepted for Jones and Brown. Green did
+ not have a mailbox at host Beta.
+
+ Example 1
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 6] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.2. FORWARDING
+
+ There are some cases where the destination information in the
+ <forward-path> is incorrect, but the receiver-SMTP knows the
+ correct destination. In such cases, one of the following replies
+ should be used to allow the sender to contact the correct
+ destination.
+
+ 251 User not local; will forward to <forward-path>
+
+ This reply indicates that the receiver-SMTP knows the user's
+ mailbox is on another host and indicates the correct
+ forward-path to use in the future. Note that either the
+ host or user or both may be different. The receiver takes
+ responsibility for delivering the message.
+
+ 551 User not local; please try <forward-path>
+
+ This reply indicates that the receiver-SMTP knows the user's
+ mailbox is on another host and indicates the correct
+ forward-path to use. Note that either the host or user or
+ both may be different. The receiver refuses to accept mail
+ for this user, and the sender must either redirect the mail
+ according to the information provided or return an error
+ response to the originating user.
+
+ Example 2 illustrates the use of these responses.
+
+ -------------------------------------------------------------
+
+ Example of Forwarding
+
+ Either
+
+ S: RCPT TO:<Postel@USC-ISI.ARPA>
+ R: 251 User not local; will forward to <Postel@USC-ISIF.ARPA>
+
+ Or
+
+ S: RCPT TO:<Paul@USC-ISIB.ARPA>
+ R: 551 User not local; please try <Mockapetris@USC-ISIF.ARPA>
+
+ Example 2
+
+ -------------------------------------------------------------
+
+
+
+
+Postel [Page 7]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.3. VERIFYING AND EXPANDING
+
+ SMTP provides as additional features, commands to verify a user
+ name or expand a mailing list. This is done with the VRFY and
+ EXPN commands, which have character string arguments. For the
+ VRFY command, the string is a user name, and the response may
+ include the full name of the user and must include the mailbox of
+ the user. For the EXPN command, the string identifies a mailing
+ list, and the multiline response may include the full name of the
+ users and must give the mailboxes on the mailing list.
+
+ "User name" is a fuzzy term and used purposely. If a host
+ implements the VRFY or EXPN commands then at least local mailboxes
+ must be recognized as "user names". If a host chooses to
+ recognize other strings as "user names" that is allowed.
+
+ In some hosts the distinction between a mailing list and an alias
+ for a single mailbox is a bit fuzzy, since a common data structure
+ may hold both types of entries, and it is possible to have mailing
+ lists of one mailbox. If a request is made to verify a mailing
+ list a positive response can be given if on receipt of a message
+ so addressed it will be delivered to everyone on the list,
+ otherwise an error should be reported (e.g., "550 That is a
+ mailing list, not a user"). If a request is made to expand a user
+ name a positive response can be formed by returning a list
+ containing one name, or an error can be reported (e.g., "550 That
+ is a user name, not a mailing list").
+
+ In the case of a multiline reply (normal for EXPN) exactly one
+ mailbox is to be specified on each line of the reply. In the case
+ of an ambiguous request, for example, "VRFY Smith", where there
+ are two Smith's the response must be "553 User ambiguous".
+
+ The case of verifying a user name is straightforward as shown in
+ example 3.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 8] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of Verifying a User Name
+
+ Either
+
+ S: VRFY Smith
+ R: 250 Fred Smith <Smith@USC-ISIF.ARPA>
+
+ Or
+
+ S: VRFY Smith
+ R: 251 User not local; will forward to <Smith@USC-ISIQ.ARPA>
+
+ Or
+
+ S: VRFY Jones
+ R: 550 String does not match anything.
+
+ Or
+
+ S: VRFY Jones
+ R: 551 User not local; please try <Jones@USC-ISIQ.ARPA>
+
+ Or
+
+ S: VRFY Gourzenkyinplatz
+ R: 553 User ambiguous.
+
+ Example 3
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 9]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The case of expanding a mailbox list requires a multiline reply as
+ shown in example 4.
+
+ -------------------------------------------------------------
+
+ Example of Expanding a Mailing List
+
+ Either
+
+ S: EXPN Example-People
+ R: 250-Jon Postel <Postel@USC-ISIF.ARPA>
+ R: 250-Fred Fonebone <Fonebone@USC-ISIQ.ARPA>
+ R: 250-Sam Q. Smith <SQSmith@USC-ISIQ.ARPA>
+ R: 250-Quincy Smith <@USC-ISIF.ARPA:Q-Smith@ISI-VAXA.ARPA>
+ R: 250-<joe@foo-unix.ARPA>
+ R: 250 <xyz@bar-unix.ARPA>
+
+ Or
+
+ S: EXPN Executive-Washroom-List
+ R: 550 Access Denied to You.
+
+ Example 4
+
+ -------------------------------------------------------------
+
+ The character string arguments of the VRFY and EXPN commands
+ cannot be further restricted due to the variety of implementations
+ of the user name and mailbox list concepts. On some systems it
+ may be appropriate for the argument of the EXPN command to be a
+ file name for a file containing a mailing list, but again there is
+ a variety of file naming conventions in the Internet.
+
+ The VRFY and EXPN commands are not included in the minimum
+ implementation (Section 4.5.1), and are not required to work
+ across relays when they are implemented.
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 10] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.4. SENDING AND MAILING
+
+ The main purpose of SMTP is to deliver messages to user's
+ mailboxes. A very similar service provided by some hosts is to
+ deliver messages to user's terminals (provided the user is active
+ on the host). The delivery to the user's mailbox is called
+ "mailing", the delivery to the user's terminal is called
+ "sending". Because in many hosts the implementation of sending is
+ nearly identical to the implementation of mailing these two
+ functions are combined in SMTP. However the sending commands are
+ not included in the required minimum implementation
+ (Section 4.5.1). Users should have the ability to control the
+ writing of messages on their terminals. Most hosts permit the
+ users to accept or refuse such messages.
+
+ The following three command are defined to support the sending
+ options. These are used in the mail transaction instead of the
+ MAIL command and inform the receiver-SMTP of the special semantics
+ of this transaction:
+
+ SEND <SP> FROM:<reverse-path> <CRLF>
+
+ The SEND command requires that the mail data be delivered to
+ the user's terminal. If the user is not active (or not
+ accepting terminal messages) on the host a 450 reply may
+ returned to a RCPT command. The mail transaction is
+ successful if the message is delivered the terminal.
+
+ SOML <SP> FROM:<reverse-path> <CRLF>
+
+ The Send Or MaiL command requires that the mail data be
+ delivered to the user's terminal if the user is active (and
+ accepting terminal messages) on the host. If the user is
+ not active (or not accepting terminal messages) then the
+ mail data is entered into the user's mailbox. The mail
+ transaction is successful if the message is delivered either
+ to the terminal or the mailbox.
+
+ SAML <SP> FROM:<reverse-path> <CRLF>
+
+ The Send And MaiL command requires that the mail data be
+ delivered to the user's terminal if the user is active (and
+ accepting terminal messages) on the host. In any case the
+ mail data is entered into the user's mailbox. The mail
+ transaction is successful if the message is delivered the
+ mailbox.
+
+
+
+Postel [Page 11]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The same reply codes that are used for the MAIL commands are used
+ for these commands.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 12] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.5. OPENING AND CLOSING
+
+ At the time the transmission channel is opened there is an
+ exchange to ensure that the hosts are communicating with the hosts
+ they think they are.
+
+ The following two commands are used in transmission channel
+ opening and closing:
+
+ HELO <SP> <domain> <CRLF>
+
+ QUIT <CRLF>
+
+ In the HELO command the host sending the command identifies
+ itself; the command may be interpreted as saying "Hello, I am
+ <domain>".
+
+ -------------------------------------------------------------
+
+ Example of Connection Opening
+
+ R: 220 BBN-UNIX.ARPA Simple Mail Transfer Service Ready
+ S: HELO USC-ISIF.ARPA
+ R: 250 BBN-UNIX.ARPA
+
+ Example 5
+
+ -------------------------------------------------------------
+
+ -------------------------------------------------------------
+
+ Example of Connection Closing
+
+ S: QUIT
+ R: 221 BBN-UNIX.ARPA Service closing transmission channel
+
+ Example 6
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+Postel [Page 13]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.6. RELAYING
+
+ The forward-path may be a source route of the form
+ "@ONE,@TWO:JOE@THREE", where ONE, TWO, and THREE are hosts. This
+ form is used to emphasize the distinction between an address and a
+ route. The mailbox is an absolute address, and the route is
+ information about how to get there. The two concepts should not
+ be confused.
+
+ Conceptually the elements of the forward-path are moved to the
+ reverse-path as the message is relayed from one server-SMTP to
+ another. The reverse-path is a reverse source route, (i.e., a
+ source route from the current location of the message to the
+ originator of the message). When a server-SMTP deletes its
+ identifier from the forward-path and inserts it into the
+ reverse-path, it must use the name it is known by in the
+ environment it is sending into, not the environment the mail came
+ from, in case the server-SMTP is known by different names in
+ different environments.
+
+ If when the message arrives at an SMTP the first element of the
+ forward-path is not the identifier of that SMTP the element is not
+ deleted from the forward-path and is used to determine the next
+ SMTP to send the message to. In any case, the SMTP adds its own
+ identifier to the reverse-path.
+
+ Using source routing the receiver-SMTP receives mail to be relayed
+ to another server-SMTP The receiver-SMTP may accept or reject the
+ task of relaying the mail in the same way it accepts or rejects
+ mail for a local user. The receiver-SMTP transforms the command
+ arguments by moving its own identifier from the forward-path to
+ the beginning of the reverse-path. The receiver-SMTP then becomes
+ a sender-SMTP, establishes a transmission channel to the next SMTP
+ in the forward-path, and sends it the mail.
+
+ The first host in the reverse-path should be the host sending the
+ SMTP commands, and the first host in the forward-path should be
+ the host receiving the SMTP commands.
+
+ Notice that the forward-path and reverse-path appear in the SMTP
+ commands and replies, but not necessarily in the message. That
+ is, there is no need for these paths and especially this syntax to
+ appear in the "To:" , "From:", "CC:", etc. fields of the message
+ header.
+
+ If a server-SMTP has accepted the task of relaying the mail and
+
+
+
+[Page 14] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ later finds that the forward-path is incorrect or that the mail
+ cannot be delivered for whatever reason, then it must construct an
+ "undeliverable mail" notification message and send it to the
+ originator of the undeliverable mail (as indicated by the
+ reverse-path).
+
+ This notification message must be from the server-SMTP at this
+ host. Of course, server-SMTPs should not send notification
+ messages about problems with notification messages. One way to
+ prevent loops in error reporting is to specify a null reverse-path
+ in the MAIL command of a notification message. When such a
+ message is relayed it is permissible to leave the reverse-path
+ null. A MAIL command with a null reverse-path appears as follows:
+
+ MAIL FROM:<>
+
+ An undeliverable mail notification message is shown in example 7.
+ This notification is in response to a message originated by JOE at
+ HOSTW and sent via HOSTX to HOSTY with instructions to relay it on
+ to HOSTZ. What we see in the example is the transaction between
+ HOSTY and HOSTX, which is the first step in the return of the
+ notification message.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 15]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example Undeliverable Mail Notification Message
+
+ S: MAIL FROM:<>
+ R: 250 ok
+ S: RCPT TO:<@HOSTX.ARPA:JOE@HOSTW.ARPA>
+ R: 250 ok
+ S: DATA
+ R: 354 send the mail data, end with .
+ S: Date: 23 Oct 81 11:22:33
+ S: From: SMTP@HOSTY.ARPA
+ S: To: JOE@HOSTW.ARPA
+ S: Subject: Mail System Problem
+ S:
+ S: Sorry JOE, your message to SAM@HOSTZ.ARPA lost.
+ S: HOSTZ.ARPA said this:
+ S: "550 No Such User"
+ S: .
+ R: 250 ok
+
+ Example 7
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 16] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 3.7. DOMAINS
+
+ Domains are a recently introduced concept in the ARPA Internet
+ mail system. The use of domains changes the address space from a
+ flat global space of simple character string host names to a
+ hierarchically structured rooted tree of global addresses. The
+ host name is replaced by a domain and host designator which is a
+ sequence of domain element strings separated by periods with the
+ understanding that the domain elements are ordered from the most
+ specific to the most general.
+
+ For example, "USC-ISIF.ARPA", "Fred.Cambridge.UK", and
+ "PC7.LCS.MIT.ARPA" might be host-and-domain identifiers.
+
+ Whenever domain names are used in SMTP only the official names are
+ used, the use of nicknames or aliases is not allowed.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 17]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 3.8. CHANGING ROLES
+
+ The TURN command may be used to reverse the roles of the two
+ programs communicating over the transmission channel.
+
+ If program-A is currently the sender-SMTP and it sends the TURN
+ command and receives an ok reply (250) then program-A becomes the
+ receiver-SMTP.
+
+ If program-B is currently the receiver-SMTP and it receives the
+ TURN command and sends an ok reply (250) then program-B becomes
+ the sender-SMTP.
+
+ To refuse to change roles the receiver sends the 502 reply.
+
+ Please note that this command is optional. It would not normally
+ be used in situations where the transmission channel is TCP.
+ However, when the cost of establishing the transmission channel is
+ high, this command may be quite useful. For example, this command
+ may be useful in supporting be mail exchange using the public
+ switched telephone system as a transmission channel, especially if
+ some hosts poll other hosts for mail exchanges.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 18] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+4. THE SMTP SPECIFICATIONS
+
+ 4.1. SMTP COMMANDS
+
+ 4.1.1. COMMAND SEMANTICS
+
+ The SMTP commands define the mail transfer or the mail system
+ function requested by the user. SMTP commands are character
+ strings terminated by <CRLF>. The command codes themselves are
+ alphabetic characters terminated by <SP> if parameters follow
+ and <CRLF> otherwise. The syntax of mailboxes must conform to
+ receiver site conventions. The SMTP commands are discussed
+ below. The SMTP replies are discussed in the Section 4.2.
+
+ A mail transaction involves several data objects which are
+ communicated as arguments to different commands. The
+ reverse-path is the argument of the MAIL command, the
+ forward-path is the argument of the RCPT command, and the mail
+ data is the argument of the DATA command. These arguments or
+ data objects must be transmitted and held pending the
+ confirmation communicated by the end of mail data indication
+ which finalizes the transaction. The model for this is that
+ distinct buffers are provided to hold the types of data
+ objects, that is, there is a reverse-path buffer, a
+ forward-path buffer, and a mail data buffer. Specific commands
+ cause information to be appended to a specific buffer, or cause
+ one or more buffers to be cleared.
+
+ HELLO (HELO)
+
+ This command is used to identify the sender-SMTP to the
+ receiver-SMTP. The argument field contains the host name of
+ the sender-SMTP.
+
+ The receiver-SMTP identifies itself to the sender-SMTP in
+ the connection greeting reply, and in the response to this
+ command.
+
+ This command and an OK reply to it confirm that both the
+ sender-SMTP and the receiver-SMTP are in the initial state,
+ that is, there is no transaction in progress and all state
+ tables and buffers are cleared.
+
+
+
+
+
+
+
+Postel [Page 19]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ MAIL (MAIL)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more mailboxes. The
+ argument field contains a reverse-path.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different). In some types of error
+ reporting messages (for example, undeliverable mail
+ notifications) the reverse-path may be null (see Example 7).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ RECIPIENT (RCPT)
+
+ This command is used to identify an individual recipient of
+ the mail data; multiple recipients are specified by multiple
+ use of this command.
+
+ The forward-path consists of an optional list of hosts and a
+ required destination mailbox. When the list of hosts is
+ present, it is a source route and indicates that the mail
+ must be relayed to the next host on the list. If the
+ receiver-SMTP does not implement the relay function it may
+ user the same reply it would for an unknown local user
+ (550).
+
+ When mail is relayed, the relay host must remove itself from
+ the beginning forward-path and put itself at the beginning
+ of the reverse-path. When mail reaches its ultimate
+ destination (the forward-path contains only a destination
+ mailbox), the receiver-SMTP inserts it into the destination
+ mailbox in accordance with its host mail conventions.
+
+
+
+
+
+[Page 20] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ For example, mail received at relay host A with arguments
+
+ FROM:<USERX@HOSTY.ARPA>
+ TO:<@HOSTA.ARPA,@HOSTB.ARPA:USERC@HOSTD.ARPA>
+
+ will be relayed on to host B with arguments
+
+ FROM:<@HOSTA.ARPA:USERX@HOSTY.ARPA>
+ TO:<@HOSTB.ARPA:USERC@HOSTD.ARPA>.
+
+ This command causes its forward-path argument to be appended
+ to the forward-path buffer.
+
+ DATA (DATA)
+
+ The receiver treats the lines following the command as mail
+ data from the sender. This command causes the mail data
+ from this command to be appended to the mail data buffer.
+ The mail data may contain any of the 128 ASCII character
+ codes.
+
+ The mail data is terminated by a line containing only a
+ period, that is the character sequence "<CRLF>.<CRLF>" (see
+ Section 4.5.2 on Transparency). This is the end of mail
+ data indication.
+
+ The end of mail data indication requires that the receiver
+ must now process the stored mail transaction information.
+ This processing consumes the information in the reverse-path
+ buffer, the forward-path buffer, and the mail data buffer,
+ and on the completion of this command these buffers are
+ cleared. If the processing is successful the receiver must
+ send an OK reply. If the processing fails completely the
+ receiver must send a failure reply.
+
+ When the receiver-SMTP accepts a message either for relaying
+ or for final delivery it inserts at the beginning of the
+ mail data a time stamp line. The time stamp line indicates
+ the identity of the host that sent the message, and the
+ identity of the host that received the message (and is
+ inserting this time stamp), and the date and time the
+ message was received. Relayed messages will have multiple
+ time stamp lines.
+
+ When the receiver-SMTP makes the "final delivery" of a
+ message it inserts at the beginning of the mail data a
+
+
+
+Postel [Page 21]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ return path line. The return path line preserves the
+ information in the <reverse-path> from the MAIL command.
+ Here, final delivery means the message leaves the SMTP
+ world. Normally, this would mean it has been delivered to
+ the destination user, but in some cases it may be further
+ processed and transmitted by another mail system.
+
+ It is possible for the mailbox in the return path be
+ different from the actual sender's mailbox, for example,
+ if error responses are to be delivered a special error
+ handling mailbox rather than the message senders.
+
+ The preceding two paragraphs imply that the final mail data
+ will begin with a return path line, followed by one or more
+ time stamp lines. These lines will be followed by the mail
+ data header and body [2]. See Example 8.
+
+ Special mention is needed of the response and further action
+ required when the processing following the end of mail data
+ indication is partially successful. This could arise if
+ after accepting several recipients and the mail data, the
+ receiver-SMTP finds that the mail data can be successfully
+ delivered to some of the recipients, but it cannot be to
+ others (for example, due to mailbox space allocation
+ problems). In such a situation, the response to the DATA
+ command must be an OK reply. But, the receiver-SMTP must
+ compose and send an "undeliverable mail" notification
+ message to the originator of the message. Either a single
+ notification which lists all of the recipients that failed
+ to get the message, or separate notification messages must
+ be sent for each failed recipient (see Example 7). All
+ undeliverable mail notification messages are sent using the
+ MAIL command (even if they result from processing a SEND,
+ SOML, or SAML command).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 22] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Example of Return Path and Received Time Stamps
+
+ Return-Path: <@GHI.ARPA,@DEF.ARPA,@ABC.ARPA:JOE@ABC.ARPA>
+ Received: from GHI.ARPA by JKL.ARPA ; 27 Oct 81 15:27:39 PST
+ Received: from DEF.ARPA by GHI.ARPA ; 27 Oct 81 15:15:13 PST
+ Received: from ABC.ARPA by DEF.ARPA ; 27 Oct 81 15:01:59 PST
+ Date: 27 Oct 81 15:01:01 PST
+ From: JOE@ABC.ARPA
+ Subject: Improved Mailing System Installed
+ To: SAM@JKL.ARPA
+
+ This is to inform you that ...
+
+ Example 8
+
+ -------------------------------------------------------------
+
+ SEND (SEND)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals. The
+ argument field contains a reverse-path. This command is
+ successful if the message is delivered to a terminal.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ SEND OR MAIL (SOML)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals or
+
+
+
+Postel [Page 23]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ mailboxes. For each recipient the mail data is delivered to
+ the recipient's terminal if the recipient is active on the
+ host (and accepting terminal messages), otherwise to the
+ recipient's mailbox. The argument field contains a
+ reverse-path. This command is successful if the message is
+ delivered to a terminal or the mailbox.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ SEND AND MAIL (SAML)
+
+ This command is used to initiate a mail transaction in which
+ the mail data is delivered to one or more terminals and
+ mailboxes. For each recipient the mail data is delivered to
+ the recipient's terminal if the recipient is active on the
+ host (and accepting terminal messages), and for all
+ recipients to the recipient's mailbox. The argument field
+ contains a reverse-path. This command is successful if the
+ message is delivered to the mailbox.
+
+ The reverse-path consists of an optional list of hosts and
+ the sender mailbox. When the list of hosts is present, it
+ is a "reverse" source route and indicates that the mail was
+ relayed through each host on the list (the first host in the
+ list was the most recent relay). This list is used as a
+ source route to return non-delivery notices to the sender.
+ As each relay host adds itself to the beginning of the list,
+ it must use its name as known in the IPCE to which it is
+ relaying the mail rather than the IPCE from which the mail
+ came (if they are different).
+
+ This command clears the reverse-path buffer, the
+
+
+
+[Page 24] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ forward-path buffer, and the mail data buffer; and inserts
+ the reverse-path information from this command into the
+ reverse-path buffer.
+
+ RESET (RSET)
+
+ This command specifies that the current mail transaction is
+ to be aborted. Any stored sender, recipients, and mail data
+ must be discarded, and all buffers and state tables cleared.
+ The receiver must send an OK reply.
+
+ VERIFY (VRFY)
+
+ This command asks the receiver to confirm that the argument
+ identifies a user. If it is a user name, the full name of
+ the user (if known) and the fully specified mailbox are
+ returned.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ EXPAND (EXPN)
+
+ This command asks the receiver to confirm that the argument
+ identifies a mailing list, and if so, to return the
+ membership of that list. The full name of the users (if
+ known) and the fully specified mailboxes are returned in a
+ multiline reply.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ HELP (HELP)
+
+ This command causes the receiver to send helpful information
+ to the sender of the HELP command. The command may take an
+ argument (e.g., any command name) and return more specific
+ information as a response.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+
+
+
+
+
+
+
+Postel [Page 25]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ NOOP (NOOP)
+
+ This command does not affect any parameters or previously
+ entered commands. It specifies no action other than that
+ the receiver send an OK reply.
+
+ This command has no effect on any of the reverse-path
+ buffer, the forward-path buffer, or the mail data buffer.
+
+ QUIT (QUIT)
+
+ This command specifies that the receiver must send an OK
+ reply, and then close the transmission channel.
+
+ The receiver should not close the transmission channel until
+ it receives and replies to a QUIT command (even if there was
+ an error). The sender should not close the transmission
+ channel until it send a QUIT command and receives the reply
+ (even if there was an error response to a previous command).
+ If the connection is closed prematurely the receiver should
+ act as if a RSET command had been received (canceling any
+ pending transaction, but not undoing any previously
+ completed transaction), the sender should act as if the
+ command or transaction in progress had received a temporary
+ error (4xx).
+
+ TURN (TURN)
+
+ This command specifies that the receiver must either (1)
+ send an OK reply and then take on the role of the
+ sender-SMTP, or (2) send a refusal reply and retain the role
+ of the receiver-SMTP.
+
+ If program-A is currently the sender-SMTP and it sends the
+ TURN command and receives an OK reply (250) then program-A
+ becomes the receiver-SMTP. Program-A is then in the initial
+ state as if the transmission channel just opened, and it
+ then sends the 220 service ready greeting.
+
+ If program-B is currently the receiver-SMTP and it receives
+ the TURN command and sends an OK reply (250) then program-B
+ becomes the sender-SMTP. Program-B is then in the initial
+ state as if the transmission channel just opened, and it
+ then expects to receive the 220 service ready greeting.
+
+ To refuse to change roles the receiver sends the 502 reply.
+
+
+
+[Page 26] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ There are restrictions on the order in which these command may
+ be used.
+
+ The first command in a session must be the HELO command.
+ The HELO command may be used later in a session as well. If
+ the HELO command argument is not acceptable a 501 failure
+ reply must be returned and the receiver-SMTP must stay in
+ the same state.
+
+ The NOOP, HELP, EXPN, and VRFY commands can be used at any
+ time during a session.
+
+ The MAIL, SEND, SOML, or SAML commands begin a mail
+ transaction. Once started a mail transaction consists of
+ one of the transaction beginning commands, one or more RCPT
+ commands, and a DATA command, in that order. A mail
+ transaction may be aborted by the RSET command. There may
+ be zero or more transactions in a session.
+
+ If the transaction beginning command argument is not
+ acceptable a 501 failure reply must be returned and the
+ receiver-SMTP must stay in the same state. If the commands
+ in a transaction are out of order a 503 failure reply must
+ be returned and the receiver-SMTP must stay in the same
+ state.
+
+ The last command in a session must be the QUIT command. The
+ QUIT command can not be used at any other time in a session.
+
+ 4.1.2. COMMAND SYNTAX
+
+ The commands consist of a command code followed by an argument
+ field. Command codes are four alphabetic characters. Upper
+ and lower case alphabetic characters are to be treated
+ identically. Thus, any of the following may represent the mail
+ command:
+
+ MAIL Mail mail MaIl mAIl
+
+ This also applies to any symbols representing parameter values,
+ such as "TO" or "to" for the forward-path. Command codes and
+ the argument fields are separated by one or more spaces.
+ However, within the reverse-path and forward-path arguments
+ case is important. In particular, in some hosts the user
+ "smith" is different from the user "Smith".
+
+
+
+
+Postel [Page 27]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The argument field consists of a variable length character
+ string ending with the character sequence <CRLF>. The receiver
+ is to take no action until this sequence is received.
+
+ Square brackets denote an optional argument field. If the
+ option is not taken, the appropriate default is implied.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 28] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ The following are the SMTP commands:
+
+ HELO <SP> <domain> <CRLF>
+
+ MAIL <SP> FROM:<reverse-path> <CRLF>
+
+ RCPT <SP> TO:<forward-path> <CRLF>
+
+ DATA <CRLF>
+
+ RSET <CRLF>
+
+ SEND <SP> FROM:<reverse-path> <CRLF>
+
+ SOML <SP> FROM:<reverse-path> <CRLF>
+
+ SAML <SP> FROM:<reverse-path> <CRLF>
+
+ VRFY <SP> <string> <CRLF>
+
+ EXPN <SP> <string> <CRLF>
+
+ HELP [<SP> <string>] <CRLF>
+
+ NOOP <CRLF>
+
+ QUIT <CRLF>
+
+ TURN <CRLF>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 29]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The syntax of the above argument fields (using BNF notation
+ where applicable) is given below. The "..." notation indicates
+ that a field may be repeated one or more times.
+
+ <reverse-path> ::= <path>
+
+ <forward-path> ::= <path>
+
+ <path> ::= "<" [ <a-d-l> ":" ] <mailbox> ">"
+
+ <a-d-l> ::= <at-domain> | <at-domain> "," <a-d-l>
+
+ <at-domain> ::= "@" <domain>
+
+ <domain> ::= <element> | <element> "." <domain>
+
+ <element> ::= <name> | "#" <number> | "[" <dotnum> "]"
+
+ <mailbox> ::= <local-part> "@" <domain>
+
+ <local-part> ::= <dot-string> | <quoted-string>
+
+ <name> ::= <a> <ldh-str> <let-dig>
+
+ <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+
+ <let-dig> ::= <a> | <d>
+
+ <let-dig-hyp> ::= <a> | <d> | "-"
+
+ <dot-string> ::= <string> | <string> "." <dot-string>
+
+ <string> ::= <char> | <char> <string>
+
+ <quoted-string> ::= """ <qtext> """
+
+ <qtext> ::= "\" <x> | "\" <x> <qtext> | <q> | <q> <qtext>
+
+ <char> ::= <c> | "\" <x>
+
+ <dotnum> ::= <snum> "." <snum> "." <snum> "." <snum>
+
+ <number> ::= <d> | <d> <number>
+
+ <CRLF> ::= <CR> <LF>
+
+
+
+
+[Page 30] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ <CR> ::= the carriage return character (ASCII code 13)
+
+ <LF> ::= the line feed character (ASCII code 10)
+
+ <SP> ::= the space character (ASCII code 32)
+
+ <snum> ::= one, two, or three digits representing a decimal
+ integer value in the range 0 through 255
+
+ <a> ::= any one of the 52 alphabetic characters A through Z
+ in upper case and a through z in lower case
+
+ <c> ::= any one of the 128 ASCII characters, but not any
+ <special> or <SP>
+
+ <d> ::= any one of the ten digits 0 through 9
+
+ <q> ::= any one of the 128 ASCII characters except <CR>,
+ <LF>, quote ("), or backslash (\)
+
+ <x> ::= any one of the 128 ASCII characters (no exceptions)
+
+ <special> ::= "<" | ">" | "(" | ")" | "[" | "]" | "\" | "."
+ | "," | ";" | ":" | "@" """ | the control
+ characters (ASCII codes 0 through 31 inclusive and
+ 127)
+
+ Note that the backslash, "\", is a quote character, which is
+ used to indicate that the next character is to be used
+ literally (instead of its normal interpretation). For example,
+ "Joe\,Smith" could be used to indicate a single nine character
+ user field with comma being the fourth character of the field.
+
+ Hosts are generally known by names which are translated to
+ addresses in each host. Note that the name elements of domains
+ are the official names -- no use of nicknames or aliases is
+ allowed.
+
+ Sometimes a host is not known to the translation function and
+ communication is blocked. To bypass this barrier two numeric
+ forms are also allowed for host "names". One form is a decimal
+ integer prefixed by a pound sign, "#", which indicates the
+ number is the address of the host. Another form is four small
+ decimal integers separated by dots and enclosed by brackets,
+ e.g., "[123.255.37.2]", which indicates a 32-bit ARPA Internet
+ Address in four 8-bit fields.
+
+
+
+Postel [Page 31]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ The time stamp line and the return path line are formally
+ defined as follows:
+
+ <return-path-line> ::= "Return-Path:" <SP><reverse-path><CRLF>
+
+ <time-stamp-line> ::= "Received:" <SP> <stamp> <CRLF>
+
+ <stamp> ::= <from-domain> <by-domain> <opt-info> ";"
+ <daytime>
+
+ <from-domain> ::= "FROM" <SP> <domain> <SP>
+
+ <by-domain> ::= "BY" <SP> <domain> <SP>
+
+ <opt-info> ::= [<via>] [<with>] [<id>] [<for>]
+
+ <via> ::= "VIA" <SP> <link> <SP>
+
+ <with> ::= "WITH" <SP> <protocol> <SP>
+
+ <id> ::= "ID" <SP> <string> <SP>
+
+ <for> ::= "FOR" <SP> <path> <SP>
+
+ <link> ::= The standard names for links are registered with
+ the Network Information Center.
+
+ <protocol> ::= The standard names for protocols are
+ registered with the Network Information Center.
+
+ <daytime> ::= <SP> <date> <SP> <time>
+
+ <date> ::= <dd> <SP> <mon> <SP> <yy>
+
+ <time> ::= <hh> ":" <mm> ":" <ss> <SP> <zone>
+
+ <dd> ::= the one or two decimal integer day of the month in
+ the range 1 to 31.
+
+ <mon> ::= "JAN" | "FEB" | "MAR" | "APR" | "MAY" | "JUN" |
+ "JUL" | "AUG" | "SEP" | "OCT" | "NOV" | "DEC"
+
+ <yy> ::= the two decimal integer year of the century in the
+ range 00 to 99.
+
+
+
+
+
+[Page 32] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ <hh> ::= the two decimal integer hour of the day in the
+ range 00 to 24.
+
+ <mm> ::= the two decimal integer minute of the hour in the
+ range 00 to 59.
+
+ <ss> ::= the two decimal integer second of the minute in the
+ range 00 to 59.
+
+ <zone> ::= "UT" for Universal Time (the default) or other
+ time zone designator (as in [2]).
+
+
+
+ -------------------------------------------------------------
+
+ Return Path Example
+
+ Return-Path: <@CHARLIE.ARPA,@BAKER.ARPA:JOE@ABLE.ARPA>
+
+ Example 9
+
+ -------------------------------------------------------------
+
+ -------------------------------------------------------------
+
+ Time Stamp Line Example
+
+ Received: FROM ABC.ARPA BY XYZ.ARPA ; 22 OCT 81 09:23:59 PDT
+
+ Received: from ABC.ARPA by XYZ.ARPA via TELENET with X25
+ id M12345 for Smith@PDQ.ARPA ; 22 OCT 81 09:23:59 PDT
+
+ Example 10
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 33]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 4.2. SMTP REPLIES
+
+ Replies to SMTP commands are devised to ensure the synchronization
+ of requests and actions in the process of mail transfer, and to
+ guarantee that the sender-SMTP always knows the state of the
+ receiver-SMTP. Every command must generate exactly one reply.
+
+ The details of the command-reply sequence are made explicit in
+ Section 5.3 on Sequencing and Section 5.4 State Diagrams.
+
+ An SMTP reply consists of a three digit number (transmitted as
+ three alphanumeric characters) followed by some text. The number
+ is intended for use by automata to determine what state to enter
+ next; the text is meant for the human user. It is intended that
+ the three digits contain enough encoded information that the
+ sender-SMTP need not examine the text and may either discard it or
+ pass it on to the user, as appropriate. In particular, the text
+ may be receiver-dependent and context dependent, so there are
+ likely to be varying texts for each reply code. A discussion of
+ the theory of reply codes is given in Appendix E. Formally, a
+ reply is defined to be the sequence: a three-digit code, <SP>,
+ one line of text, and <CRLF>, or a multiline reply (as defined in
+ Appendix E). Only the EXPN and HELP commands are expected to
+ result in multiline replies in normal circumstances, however
+ multiline replies are allowed for any command.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 34] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 4.2.1. REPLY CODES BY FUNCTION GROUPS
+
+ 500 Syntax error, command unrecognized
+ [This may include errors such as command line too long]
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+
+ 211 System status, or system help reply
+ 214 Help message
+ [Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user]
+
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 421 <domain> Service not available,
+ closing transmission channel
+ [This may be a reply to any command if the service knows it
+ must shut down]
+
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+ 450 Requested mail action not taken: mailbox unavailable
+ [E.g., mailbox busy]
+ 550 Requested action not taken: mailbox unavailable
+ [E.g., mailbox not found, no access]
+ 451 Requested action aborted: error in processing
+ 551 User not local; please try <forward-path>
+ 452 Requested action not taken: insufficient system storage
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ [E.g., mailbox syntax incorrect]
+ 354 Start mail input; end with <CRLF>.<CRLF>
+ 554 Transaction failed
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 35]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ 4.2.2. NUMERIC ORDER LIST OF REPLY CODES
+
+ 211 System status, or system help reply
+ 214 Help message
+ [Information on how to use the receiver or the meaning of a
+ particular non-standard command; this reply is useful only
+ to the human user]
+ 220 <domain> Service ready
+ 221 <domain> Service closing transmission channel
+ 250 Requested mail action okay, completed
+ 251 User not local; will forward to <forward-path>
+
+ 354 Start mail input; end with <CRLF>.<CRLF>
+
+ 421 <domain> Service not available,
+ closing transmission channel
+ [This may be a reply to any command if the service knows it
+ must shut down]
+ 450 Requested mail action not taken: mailbox unavailable
+ [E.g., mailbox busy]
+ 451 Requested action aborted: local error in processing
+ 452 Requested action not taken: insufficient system storage
+
+ 500 Syntax error, command unrecognized
+ [This may include errors such as command line too long]
+ 501 Syntax error in parameters or arguments
+ 502 Command not implemented
+ 503 Bad sequence of commands
+ 504 Command parameter not implemented
+ 550 Requested action not taken: mailbox unavailable
+ [E.g., mailbox not found, no access]
+ 551 User not local; please try <forward-path>
+ 552 Requested mail action aborted: exceeded storage allocation
+ 553 Requested action not taken: mailbox name not allowed
+ [E.g., mailbox syntax incorrect]
+ 554 Transaction failed
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 36] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 4.3. SEQUENCING OF COMMANDS AND REPLIES
+
+ The communication between the sender and receiver is intended to
+ be an alternating dialogue, controlled by the sender. As such,
+ the sender issues a command and the receiver responds with a
+ reply. The sender must wait for this response before sending
+ further commands.
+
+ One important reply is the connection greeting. Normally, a
+ receiver will send a 220 "Service ready" reply when the connection
+ is completed. The sender should wait for this greeting message
+ before sending any commands.
+
+ Note: all the greeting type replies have the official name of
+ the server host as the first word following the reply code.
+
+ For example,
+
+ 220 <SP> USC-ISIF.ARPA <SP> Service ready <CRLF>
+
+ The table below lists alternative success and failure replies for
+ each command. These must be strictly adhered to; a receiver may
+ substitute text in the replies, but the meaning and action implied
+ by the code numbers and by the specific command reply sequence
+ cannot be altered.
+
+ COMMAND-REPLY SEQUENCES
+
+ Each command is listed with its possible replies. The prefixes
+ used before the possible replies are "P" for preliminary (not
+ used in SMTP), "I" for intermediate, "S" for success, "F" for
+ failure, and "E" for error. The 421 reply (service not
+ available, closing transmission channel) may be given to any
+ command if the SMTP-receiver knows it must shut down. This
+ listing forms the basis for the State Diagrams in Section 4.4.
+
+ CONNECTION ESTABLISHMENT
+ S: 220
+ F: 421
+ HELO
+ S: 250
+ E: 500, 501, 504, 421
+ MAIL
+ S: 250
+ F: 552, 451, 452
+ E: 500, 501, 421
+
+
+
+Postel [Page 37]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ RCPT
+ S: 250, 251
+ F: 550, 551, 552, 553, 450, 451, 452
+ E: 500, 501, 503, 421
+ DATA
+ I: 354 -> data -> S: 250
+ F: 552, 554, 451, 452
+ F: 451, 554
+ E: 500, 501, 503, 421
+ RSET
+ S: 250
+ E: 500, 501, 504, 421
+ SEND
+ S: 250
+ F: 552, 451, 452
+ E: 500, 501, 502, 421
+ SOML
+ S: 250
+ F: 552, 451, 452
+ E: 500, 501, 502, 421
+ SAML
+ S: 250
+ F: 552, 451, 452
+ E: 500, 501, 502, 421
+ VRFY
+ S: 250, 251
+ F: 550, 551, 553
+ E: 500, 501, 502, 504, 421
+ EXPN
+ S: 250
+ F: 550
+ E: 500, 501, 502, 504, 421
+ HELP
+ S: 211, 214
+ E: 500, 501, 502, 504, 421
+ NOOP
+ S: 250
+ E: 500, 421
+ QUIT
+ S: 221
+ E: 500
+ TURN
+ S: 250
+ F: 502
+ E: 500, 503
+
+
+
+
+[Page 38] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 4.4. STATE DIAGRAMS
+
+ Following are state diagrams for a simple-minded SMTP
+ implementation. Only the first digit of the reply codes is used.
+ There is one state diagram for each group of SMTP commands. The
+ command groupings were determined by constructing a model for each
+ command and then collecting together the commands with
+ structurally identical models.
+
+ For each command there are three possible outcomes: "success"
+ (S), "failure" (F), and "error" (E). In the state diagrams below
+ we use the symbol B for "begin", and the symbol W for "wait for
+ reply".
+
+ First, the diagram that represents most of the SMTP commands:
+
+
+ 1,3 +---+
+ ----------->| E |
+ | +---+
+ |
+ +---+ cmd +---+ 2 +---+
+ | B |---------->| W |---------->| S |
+ +---+ +---+ +---+
+ |
+ | 4,5 +---+
+ ----------->| F |
+ +---+
+
+
+ This diagram models the commands:
+
+ HELO, MAIL, RCPT, RSET, SEND, SOML, SAML, VRFY, EXPN, HELP,
+ NOOP, QUIT, TURN.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 39]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ A more complex diagram models the DATA command:
+
+
+ +---+ DATA +---+ 1,2 +---+
+ | B |---------->| W |-------------------->| E |
+ +---+ +---+ ------------>+---+
+ 3| |4,5 |
+ | | |
+ -------------- ----- |
+ | | | +---+
+ | ---------- -------->| S |
+ | | | | +---+
+ | | ------------
+ | | | |
+ V 1,3| |2 |
+ +---+ data +---+ --------------->+---+
+ | |---------->| W | | F |
+ +---+ +---+-------------------->+---+
+ 4,5
+
+
+ Note that the "data" here is a series of lines sent from the
+ sender to the receiver with no response expected until the last
+ line is sent.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 40] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ 4.5. DETAILS
+
+ 4.5.1. MINIMUM IMPLEMENTATION
+
+ In order to make SMTP workable, the following minimum
+ implementation is required for all receivers:
+
+ COMMANDS -- HELO
+ MAIL
+ RCPT
+ DATA
+ RSET
+ NOOP
+ QUIT
+
+ 4.5.2. TRANSPARENCY
+
+ Without some provision for data transparency the character
+ sequence "<CRLF>.<CRLF>" ends the mail text and cannot be sent
+ by the user. In general, users are not aware of such
+ "forbidden" sequences. To allow all user composed text to be
+ transmitted transparently the following procedures are used.
+
+ 1. Before sending a line of mail text the sender-SMTP checks
+ the first character of the line. If it is a period, one
+ additional period is inserted at the beginning of the line.
+
+ 2. When a line of mail text is received by the receiver-SMTP
+ it checks the line. If the line is composed of a single
+ period it is the end of mail. If the first character is a
+ period and there are other characters on the line, the first
+ character is deleted.
+
+ The mail data may contain any of the 128 ASCII characters. All
+ characters are to be delivered to the recipient's mailbox
+ including format effectors and other control characters. If
+ the transmission channel provides an 8-bit byte (octets) data
+ stream, the 7-bit ASCII codes are transmitted right justified
+ in the octets with the high order bits cleared to zero.
+
+ In some systems it may be necessary to transform the data as
+ it is received and stored. This may be necessary for hosts
+ that use a different character set than ASCII as their local
+ character set, or that store data in records rather than
+
+
+
+
+
+Postel [Page 41]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ strings. If such transforms are necessary, they must be
+ reversible -- especially if such transforms are applied to
+ mail being relayed.
+
+ 4.5.3. SIZES
+
+ There are several objects that have required minimum maximum
+ sizes. That is, every implementation must be able to receive
+ objects of at least these sizes, but must not send objects
+ larger than these sizes.
+
+
+ ****************************************************
+ * *
+ * TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
+ * TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
+ * OF THESE OBJECTS SHOULD BE USED. *
+ * *
+ ****************************************************
+
+ user
+
+ The maximum total length of a user name is 64 characters.
+
+ domain
+
+ The maximum total length of a domain name or number is 64
+ characters.
+
+ path
+
+ The maximum total length of a reverse-path or
+ forward-path is 256 characters (including the punctuation
+ and element separators).
+
+ command line
+
+ The maximum total length of a command line including the
+ command word and the <CRLF> is 512 characters.
+
+ reply line
+
+ The maximum total length of a reply line including the
+ reply code and the <CRLF> is 512 characters.
+
+
+
+
+
+[Page 42] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ text line
+
+ The maximum total length of a text line including the
+ <CRLF> is 1000 characters (but not counting the leading
+ dot duplicated for transparency).
+
+ recipients buffer
+
+ The maximum total number of recipients that must be
+ buffered is 100 recipients.
+
+
+ ****************************************************
+ * *
+ * TO THE MAXIMUM EXTENT POSSIBLE, IMPLEMENTATION *
+ * TECHNIQUES WHICH IMPOSE NO LIMITS ON THE LENGTH *
+ * OF THESE OBJECTS SHOULD BE USED. *
+ * *
+ ****************************************************
+
+ Errors due to exceeding these limits may be reported by using
+ the reply codes, for example:
+
+ 500 Line too long.
+
+ 501 Path too long
+
+ 552 Too many recipients.
+
+ 552 Too much mail data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 43]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+APPENDIX A
+
+ TCP Transport service
+
+ The Transmission Control Protocol [3] is used in the ARPA
+ Internet, and in any network following the US DoD standards for
+ internetwork protocols.
+
+ Connection Establishment
+
+ The SMTP transmission channel is a TCP connection established
+ between the sender process port U and the receiver process port
+ L. This single full duplex connection is used as the
+ transmission channel. This protocol is assigned the service
+ port 25 (31 octal), that is L=25.
+
+ Data Transfer
+
+ The TCP connection supports the transmission of 8-bit bytes.
+ The SMTP data is 7-bit ASCII characters. Each character is
+ transmitted as an 8-bit byte with the high-order bit cleared to
+ zero.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 44] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+APPENDIX B
+
+ NCP Transport service
+
+ The ARPANET Host-to-Host Protocol [4] (implemented by the Network
+ Control Program) may be used in the ARPANET.
+
+ Connection Establishment
+
+ The SMTP transmission channel is established via NCP between
+ the sender process socket U and receiver process socket L. The
+ Initial Connection Protocol [5] is followed resulting in a pair
+ of simplex connections. This pair of connections is used as
+ the transmission channel. This protocol is assigned the
+ contact socket 25 (31 octal), that is L=25.
+
+ Data Transfer
+
+ The NCP data connections are established in 8-bit byte mode.
+ The SMTP data is 7-bit ASCII characters. Each character is
+ transmitted as an 8-bit byte with the high-order bit cleared to
+ zero.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 45]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+APPENDIX C
+
+ NITS
+
+ The Network Independent Transport Service [6] may be used.
+
+ Connection Establishment
+
+ The SMTP transmission channel is established via NITS between
+ the sender process and receiver process. The sender process
+ executes the CONNECT primitive, and the waiting receiver
+ process executes the ACCEPT primitive.
+
+ Data Transfer
+
+ The NITS connection supports the transmission of 8-bit bytes.
+ The SMTP data is 7-bit ASCII characters. Each character is
+ transmitted as an 8-bit byte with the high-order bit cleared to
+ zero.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 46] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+APPENDIX D
+
+ X.25 Transport service
+
+ It may be possible to use the X.25 service [7] as provided by the
+ Public Data Networks directly, however, it is suggested that a
+ reliable end-to-end protocol such as TCP be used on top of X.25
+ connections.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 47]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+APPENDIX E
+
+ Theory of Reply Codes
+
+ The three digits of the reply each have a special significance.
+ The first digit denotes whether the response is good, bad or
+ incomplete. An unsophisticated sender-SMTP will be able to
+ determine its next action (proceed as planned, redo, retrench,
+ etc.) by simply examining this first digit. A sender-SMTP that
+ wants to know approximately what kind of error occurred (e.g.,
+ mail system error, command syntax error) may examine the second
+ digit, reserving the third digit for the finest gradation of
+ information.
+
+ There are five values for the first digit of the reply code:
+
+ 1yz Positive Preliminary reply
+
+ The command has been accepted, but the requested action
+ is being held in abeyance, pending confirmation of the
+ information in this reply. The sender-SMTP should send
+ another command specifying whether to continue or abort
+ the action.
+
+ [Note: SMTP does not have any commands that allow this
+ type of reply, and so does not have the continue or
+ abort commands.]
+
+ 2yz Positive Completion reply
+
+ The requested action has been successfully completed. A
+ new request may be initiated.
+
+ 3yz Positive Intermediate reply
+
+ The command has been accepted, but the requested action
+ is being held in abeyance, pending receipt of further
+ information. The sender-SMTP should send another command
+ specifying this information. This reply is used in
+ command sequence groups.
+
+ 4yz Transient Negative Completion reply
+
+ The command was not accepted and the requested action did
+ not occur. However, the error condition is temporary and
+ the action may be requested again. The sender should
+
+
+
+[Page 48] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ return to the beginning of the command sequence (if any).
+ It is difficult to assign a meaning to "transient" when
+ two different sites (receiver- and sender- SMTPs) must
+ agree on the interpretation. Each reply in this category
+ might have a different time value, but the sender-SMTP is
+ encouraged to try again. A rule of thumb to determine if
+ a reply fits into the 4yz or the 5yz category (see below)
+ is that replies are 4yz if they can be repeated without
+ any change in command form or in properties of the sender
+ or receiver. (E.g., the command is repeated identically
+ and the receiver does not put up a new implementation.)
+
+ 5yz Permanent Negative Completion reply
+
+ The command was not accepted and the requested action did
+ not occur. The sender-SMTP is discouraged from repeating
+ the exact request (in the same sequence). Even some
+ "permanent" error conditions can be corrected, so the
+ human user may want to direct the sender-SMTP to
+ reinitiate the command sequence by direct action at some
+ point in the future (e.g., after the spelling has been
+ changed, or the user has altered the account status).
+
+ The second digit encodes responses in specific categories:
+
+ x0z Syntax -- These replies refer to syntax errors,
+ syntactically correct commands that don't fit any
+ functional category, and unimplemented or superfluous
+ commands.
+
+ x1z Information -- These are replies to requests for
+ information, such as status or help.
+
+ x2z Connections -- These are replies referring to the
+ transmission channel.
+
+ x3z Unspecified as yet.
+
+ x4z Unspecified as yet.
+
+ x5z Mail system -- These replies indicate the status of
+ the receiver mail system vis-a-vis the requested
+ transfer or other mail system action.
+
+ The third digit gives a finer gradation of meaning in each
+ category specified by the second digit. The list of replies
+
+
+
+Postel [Page 49]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ illustrates this. Each reply text is recommended rather than
+ mandatory, and may even change according to the command with
+ which it is associated. On the other hand, the reply codes
+ must strictly follow the specifications in this section.
+ Receiver implementations should not invent new codes for
+ slightly different situations from the ones described here, but
+ rather adapt codes already defined.
+
+ For example, a command such as NOOP whose successful execution
+ does not offer the sender-SMTP any new information will return
+ a 250 reply. The response is 502 when the command requests an
+ unimplemented non-site-specific action. A refinement of that
+ is the 504 reply for a command that is implemented, but that
+ requests an unimplemented parameter.
+
+ The reply text may be longer than a single line; in these cases
+ the complete text must be marked so the sender-SMTP knows when it
+ can stop reading the reply. This requires a special format to
+ indicate a multiple line reply.
+
+ The format for multiline replies requires that every line,
+ except the last, begin with the reply code, followed
+ immediately by a hyphen, "-" (also known as minus), followed by
+ text. The last line will begin with the reply code, followed
+ immediately by <SP>, optionally some text, and <CRLF>.
+
+ For example:
+ 123-First line
+ 123-Second line
+ 123-234 text beginning with numbers
+ 123 The last line
+
+ In many cases the sender-SMTP then simply needs to search for
+ the reply code followed by <SP> at the beginning of a line, and
+ ignore all preceding lines. In a few cases, there is important
+ data for the sender in the reply "text". The sender will know
+ these cases from the current context.
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 50] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+APPENDIX F
+
+ Scenarios
+
+ This section presents complete scenarios of several types of SMTP
+ sessions.
+
+ A Typical SMTP Transaction Scenario
+
+ This SMTP example shows mail sent by Smith at host USC-ISIF, to
+ Jones, Green, and Brown at host BBN-UNIX. Here we assume that
+ host USC-ISIF contacts host BBN-UNIX directly. The mail is
+ accepted for Jones and Brown. Green does not have a mailbox at
+ host BBN-UNIX.
+
+ -------------------------------------------------------------
+
+ R: 220 BBN-UNIX.ARPA Simple Mail Transfer Service Ready
+ S: HELO USC-ISIF.ARPA
+ R: 250 BBN-UNIX.ARPA
+
+ S: MAIL FROM:<Smith@USC-ISIF.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Jones@BBN-UNIX.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Green@BBN-UNIX.ARPA>
+ R: 550 No such user here
+
+ S: RCPT TO:<Brown@BBN-UNIX.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 BBN-UNIX.ARPA Service closing transmission channel
+
+ Scenario 1
+
+ -------------------------------------------------------------
+
+
+
+Postel [Page 51]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ Aborted SMTP Transaction Scenario
+
+ -------------------------------------------------------------
+
+ R: 220 MIT-Multics.ARPA Simple Mail Transfer Service Ready
+ S: HELO ISI-VAXA.ARPA
+ R: 250 MIT-Multics.ARPA
+
+ S: MAIL FROM:<Smith@ISI-VAXA.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Jones@MIT-Multics.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Green@MIT-Multics.ARPA>
+ R: 550 No such user here
+
+ S: RSET
+ R: 250 OK
+
+ S: QUIT
+ R: 221 MIT-Multics.ARPA Service closing transmission channel
+
+ Scenario 2
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 52] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Relayed Mail Scenario
+
+ -------------------------------------------------------------
+
+ Step 1 -- Source Host to Relay Host
+
+ R: 220 USC-ISIE.ARPA Simple Mail Transfer Service Ready
+ S: HELO MIT-AI.ARPA
+ R: 250 USC-ISIE.ARPA
+
+ S: MAIL FROM:<JQP@MIT-AI.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<@USC-ISIE.ARPA:Jones@BBN-VAX.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Date: 2 Nov 81 22:33:44
+ S: From: John Q. Public <JQP@MIT-AI.ARPA>
+ S: Subject: The Next Meeting of the Board
+ S: To: Jones@BBN-Vax.ARPA
+ S:
+ S: Bill:
+ S: The next meeting of the board of directors will be
+ S: on Tuesday.
+ S: John.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISIE.ARPA Service closing transmission channel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 53]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ Step 2 -- Relay Host to Destination Host
+
+ R: 220 BBN-VAX.ARPA Simple Mail Transfer Service Ready
+ S: HELO USC-ISIE.ARPA
+ R: 250 BBN-VAX.ARPA
+
+ S: MAIL FROM:<@USC-ISIE.ARPA:JQP@MIT-AI.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Jones@BBN-VAX.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Received: from MIT-AI.ARPA by USC-ISIE.ARPA ;
+ 2 Nov 81 22:40:10 UT
+ S: Date: 2 Nov 81 22:33:44
+ S: From: John Q. Public <JQP@MIT-AI.ARPA>
+ S: Subject: The Next Meeting of the Board
+ S: To: Jones@BBN-Vax.ARPA
+ S:
+ S: Bill:
+ S: The next meeting of the board of directors will be
+ S: on Tuesday.
+ S: John.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISIE.ARPA Service closing transmission channel
+
+ Scenario 3
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 54] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Verifying and Sending Scenario
+
+ -------------------------------------------------------------
+
+ R: 220 SU-SCORE.ARPA Simple Mail Transfer Service Ready
+ S: HELO MIT-MC.ARPA
+ R: 250 SU-SCORE.ARPA
+
+ S: VRFY Crispin
+ R: 250 Mark Crispin <Admin.MRC@SU-SCORE.ARPA>
+
+ S: SEND FROM:<EAK@MIT-MC.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Admin.MRC@SU-SCORE.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 SU-SCORE.ARPA Service closing transmission channel
+
+ Scenario 4
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 55]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ Sending and Mailing Scenarios
+
+ First the user's name is verified, then an attempt is made to
+ send to the user's terminal. When that fails, the messages is
+ mailed to the user's mailbox.
+
+ -------------------------------------------------------------
+
+ R: 220 SU-SCORE.ARPA Simple Mail Transfer Service Ready
+ S: HELO MIT-MC.ARPA
+ R: 250 SU-SCORE.ARPA
+
+ S: VRFY Crispin
+ R: 250 Mark Crispin <Admin.MRC@SU-SCORE.ARPA>
+
+ S: SEND FROM:<EAK@MIT-MC.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Admin.MRC@SU-SCORE.ARPA>
+ R: 450 User not active now
+
+ S: RSET
+ R: 250 OK
+
+ S: MAIL FROM:<EAK@MIT-MC.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Admin.MRC@SU-SCORE.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 SU-SCORE.ARPA Service closing transmission channel
+
+ Scenario 5
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+[Page 56] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Doing the preceding scenario more efficiently.
+
+ -------------------------------------------------------------
+
+ R: 220 SU-SCORE.ARPA Simple Mail Transfer Service Ready
+ S: HELO MIT-MC.ARPA
+ R: 250 SU-SCORE.ARPA
+
+ S: VRFY Crispin
+ R: 250 Mark Crispin <Admin.MRC@SU-SCORE.ARPA>
+
+ S: SOML FROM:<EAK@MIT-MC.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Admin.MRC@SU-SCORE.ARPA>
+ R: 250 User not active now, so will do mail.
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 SU-SCORE.ARPA Service closing transmission channel
+
+ Scenario 6
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 57]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ Mailing List Scenario
+
+ First each of two mailing lists are expanded in separate sessions
+ with different hosts. Then the message is sent to everyone that
+ appeared on either list (but no duplicates) via a relay host.
+
+ -------------------------------------------------------------
+
+ Step 1 -- Expanding the First List
+
+ R: 220 MIT-AI.ARPA Simple Mail Transfer Service Ready
+ S: HELO SU-SCORE.ARPA
+ R: 250 MIT-AI.ARPA
+
+ S: EXPN Example-People
+ R: 250-<ABC@MIT-MC.ARPA>
+ R: 250-Fred Fonebone <Fonebone@USC-ISIQ.ARPA>
+ R: 250-Xenon Y. Zither <XYZ@MIT-AI.ARPA>
+ R: 250-Quincy Smith <@USC-ISIF.ARPA:Q-Smith@ISI-VAXA.ARPA>
+ R: 250-<joe@foo-unix.ARPA>
+ R: 250 <xyz@bar-unix.ARPA>
+
+ S: QUIT
+ R: 221 MIT-AI.ARPA Service closing transmission channel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 58] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Step 2 -- Expanding the Second List
+
+ R: 220 MIT-MC.ARPA Simple Mail Transfer Service Ready
+ S: HELO SU-SCORE.ARPA
+ R: 250 MIT-MC.ARPA
+
+ S: EXPN Interested-Parties
+ R: 250-Al Calico <ABC@MIT-MC.ARPA>
+ R: 250-<XYZ@MIT-AI.ARPA>
+ R: 250-Quincy Smith <@USC-ISIF.ARPA:Q-Smith@ISI-VAXA.ARPA>
+ R: 250-<fred@BBN-UNIX.ARPA>
+ R: 250 <xyz@bar-unix.ARPA>
+
+ S: QUIT
+ R: 221 MIT-MC.ARPA Service closing transmission channel
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 59]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ Step 3 -- Mailing to All via a Relay Host
+
+ R: 220 USC-ISIE.ARPA Simple Mail Transfer Service Ready
+ S: HELO SU-SCORE.ARPA
+ R: 250 USC-ISIE.ARPA
+
+ S: MAIL FROM:<Account.Person@SU-SCORE.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:ABC@MIT-MC.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:Fonebone@USC-ISIQA.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:XYZ@MIT-AI.ARPA>
+ R: 250 OK
+ S: RCPT
+ TO:<@USC-ISIE.ARPA,@USC-ISIF.ARPA:Q-Smith@ISI-VAXA.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:joe@FOO-UNIX.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:xyz@BAR-UNIX.ARPA>
+ R: 250 OK
+ S: RCPT TO:<@USC-ISIE.ARPA:fred@BBN-UNIX.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISIE.ARPA Service closing transmission channel
+
+ Scenario 7
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 60] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Forwarding Scenarios
+
+ -------------------------------------------------------------
+
+ R: 220 USC-ISIF.ARPA Simple Mail Transfer Service Ready
+ S: HELO LBL-UNIX.ARPA
+ R: 250 USC-ISIF.ARPA
+
+ S: MAIL FROM:<mo@LBL-UNIX.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<fred@USC-ISIF.ARPA>
+ R: 251 User not local; will forward to <Jones@USC-ISI.ARPA>
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISIF.ARPA Service closing transmission channel
+
+ Scenario 8
+
+ -------------------------------------------------------------
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Postel [Page 61]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ -------------------------------------------------------------
+
+ Step 1 -- Trying the Mailbox at the First Host
+
+ R: 220 USC-ISIF.ARPA Simple Mail Transfer Service Ready
+ S: HELO LBL-UNIX.ARPA
+ R: 250 USC-ISIF.ARPA
+
+ S: MAIL FROM:<mo@LBL-UNIX.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<fred@USC-ISIF.ARPA>
+ R: 251 User not local; will forward to <Jones@USC-ISI.ARPA>
+
+ S: RSET
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISIF.ARPA Service closing transmission channel
+
+ Step 2 -- Delivering the Mail at the Second Host
+
+ R: 220 USC-ISI.ARPA Simple Mail Transfer Service Ready
+ S: HELO LBL-UNIX.ARPA
+ R: 250 USC-ISI.ARPA
+
+ S: MAIL FROM:<mo@LBL-UNIX.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<Jones@USC-ISI.ARPA>
+ R: OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 USC-ISI.ARPA Service closing transmission channel
+
+ Scenario 9
+
+ -------------------------------------------------------------
+
+
+
+
+[Page 62] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ Too Many Recipients Scenario
+
+ -------------------------------------------------------------
+
+ R: 220 BERKELEY.ARPA Simple Mail Transfer Service Ready
+ S: HELO USC-ISIF.ARPA
+ R: 250 BERKELEY.ARPA
+
+ S: MAIL FROM:<Postel@USC-ISIF.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<fabry@BERKELEY.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<eric@BERKELEY.ARPA>
+ R: 552 Recipient storage full, try again in another transaction
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: MAIL FROM:<Postel@USC-ISIF.ARPA>
+ R: 250 OK
+
+ S: RCPT TO:<eric@BERKELEY.ARPA>
+ R: 250 OK
+
+ S: DATA
+ R: 354 Start mail input; end with <CRLF>.<CRLF>
+ S: Blah blah blah...
+ S: ...etc. etc. etc.
+ S: .
+ R: 250 OK
+
+ S: QUIT
+ R: 221 BERKELEY.ARPA Service closing transmission channel
+
+ Scenario 10
+
+ -------------------------------------------------------------
+
+ Note that a real implementation must handle many recipients as
+ specified in Section 4.5.3.
+
+
+
+Postel [Page 63]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+GLOSSARY
+
+ ASCII
+
+ American Standard Code for Information Interchange [1].
+
+ command
+
+ A request for a mail service action sent by the sender-SMTP to the
+ receiver-SMTP.
+
+ domain
+
+ The hierarchially structured global character string address of a
+ host computer in the mail system.
+
+ end of mail data indication
+
+ A special sequence of characters that indicates the end of the
+ mail data. In particular, the five characters carriage return,
+ line feed, period, carriage return, line feed, in that order.
+
+ host
+
+ A computer in the internetwork environment on which mailboxes or
+ SMTP processes reside.
+
+ line
+
+ A a sequence of ASCII characters ending with a <CRLF>.
+
+ mail data
+
+ A sequence of ASCII characters of arbitrary length, which conforms
+ to the standard set in the Standard for the Format of ARPA
+ Internet Text Messages (RFC 822 [2]).
+
+ mailbox
+
+ A character string (address) which identifies a user to whom mail
+ is to be sent. Mailbox normally consists of the host and user
+ specifications. The standard mailbox naming convention is defined
+ to be "user@domain". Additionally, the "container" in which mail
+ is stored.
+
+
+
+
+
+[Page 64] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+ receiver-SMTP process
+
+ A process which transfers mail in cooperation with a sender-SMTP
+ process. It waits for a connection to be established via the
+ transport service. It receives SMTP commands from the
+ sender-SMTP, sends replies, and performs the specified operations.
+
+ reply
+
+ A reply is an acknowledgment (positive or negative) sent from
+ receiver to sender via the transmission channel in response to a
+ command. The general form of a reply is a completion code
+ (including error codes) followed by a text string. The codes are
+ for use by programs and the text is usually intended for human
+ users.
+
+ sender-SMTP process
+
+ A process which transfers mail in cooperation with a receiver-SMTP
+ process. A local language may be used in the user interface
+ command/reply dialogue. The sender-SMTP initiates the transport
+ service connection. It initiates SMTP commands, receives replies,
+ and governs the transfer of mail.
+
+ session
+
+ The set of exchanges that occur while the transmission channel is
+ open.
+
+ transaction
+
+ The set of exchanges required for one message to be transmitted
+ for one or more recipients.
+
+ transmission channel
+
+ A full-duplex communication path between a sender-SMTP and a
+ receiver-SMTP for the exchange of commands, replies, and mail
+ text.
+
+ transport service
+
+ Any reliable stream-oriented data communication services. For
+ example, NCP, TCP, NITS.
+
+
+
+
+
+Postel [Page 65]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ user
+
+ A human being (or a process on behalf of a human being) wishing to
+ obtain mail transfer service. In addition, a recipient of
+ computer mail.
+
+ word
+
+ A sequence of printing characters.
+
+ <CRLF>
+
+ The characters carriage return and line feed (in that order).
+
+ <SP>
+
+ The space character.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 66] Postel
+
+
+
+RFC 821 August 1982
+ Simple Mail Transfer Protocol
+
+
+
+REFERENCES
+
+ [1] ASCII
+
+ ASCII, "USA Code for Information Interchange", United States of
+ America Standards Institute, X3.4, 1968. Also in: Feinler, E.
+ and J. Postel, eds., "ARPANET Protocol Handbook", NIC 7104, for
+ the Defense Communications Agency by SRI International, Menlo
+ Park, California, Revised January 1978.
+
+ [2] RFC 822
+
+ Crocker, D., "Standard for the Format of ARPA Internet Text
+ Messages," RFC 822, Department of Electrical Engineering,
+ University of Delaware, August 1982.
+
+ [3] TCP
+
+ Postel, J., ed., "Transmission Control Protocol - DARPA Internet
+ Program Protocol Specification", RFC 793, USC/Information Sciences
+ Institute, NTIS AD Number A111091, September 1981. Also in:
+ Feinler, E. and J. Postel, eds., "Internet Protocol Transition
+ Workbook", SRI International, Menlo Park, California, March 1982.
+
+ [4] NCP
+
+ McKenzie,A., "Host/Host Protocol for the ARPA Network", NIC 8246,
+ January 1972. Also in: Feinler, E. and J. Postel, eds., "ARPANET
+ Protocol Handbook", NIC 7104, for the Defense Communications
+ Agency by SRI International, Menlo Park, California, Revised
+ January 1978.
+
+ [5] Initial Connection Protocol
+
+ Postel, J., "Official Initial Connection Protocol", NIC 7101,
+ 11 June 1971. Also in: Feinler, E. and J. Postel, eds., "ARPANET
+ Protocol Handbook", NIC 7104, for the Defense Communications
+ Agency by SRI International, Menlo Park, California, Revised
+ January 1978.
+
+ [6] NITS
+
+ PSS/SG3, "A Network Independent Transport Service", Study Group 3,
+ The Post Office PSS Users Group, February 1980. Available from
+ the DCPU, National Physical Laboratory, Teddington, UK.
+
+
+
+
+Postel [Page 67]
+
+
+
+August 1982 RFC 821
+Simple Mail Transfer Protocol
+
+
+
+ [7] X.25
+
+ CCITT, "Recommendation X.25 - Interface Between Data Terminal
+ Equipment (DTE) and Data Circuit-terminating Equipment (DCE) for
+ Terminals Operating in the Packet Mode on Public Data Networks,"
+ CCITT Orange Book, Vol. VIII.2, International Telephone and
+ Telegraph Consultative Committee, Geneva, 1976.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+[Page 68] Postel
+
diff --git a/usr.sbin/sendmail/doc/rfc/rfc822.txt b/usr.sbin/sendmail/doc/rfc/rfc822.txt
new file mode 100644
index 0000000..35b09a3
--- /dev/null
+++ b/usr.sbin/sendmail/doc/rfc/rfc822.txt
@@ -0,0 +1,2901 @@
+
+
+
+
+
+
+ RFC # 822
+
+ Obsoletes: RFC #733 (NIC #41952)
+
+
+
+
+
+
+
+
+
+
+
+
+ STANDARD FOR THE FORMAT OF
+
+ ARPA INTERNET TEXT MESSAGES
+
+
+
+
+
+
+ August 13, 1982
+
+
+
+
+
+
+ Revised by
+
+ David H. Crocker
+
+
+ Dept. of Electrical Engineering
+ University of Delaware, Newark, DE 19711
+ Network: DCrocker @ UDel-Relay
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ TABLE OF CONTENTS
+
+
+ PREFACE .................................................... ii
+
+ 1. INTRODUCTION ........................................... 1
+
+ 1.1. Scope ............................................ 1
+ 1.2. Communication Framework .......................... 2
+
+ 2. NOTATIONAL CONVENTIONS ................................. 3
+
+ 3. LEXICAL ANALYSIS OF MESSAGES ........................... 5
+
+ 3.1. General Description .............................. 5
+ 3.2. Header Field Definitions ......................... 9
+ 3.3. Lexical Tokens ................................... 10
+ 3.4. Clarifications ................................... 11
+
+ 4. MESSAGE SPECIFICATION .................................. 17
+
+ 4.1. Syntax ........................................... 17
+ 4.2. Forwarding ....................................... 19
+ 4.3. Trace Fields ..................................... 20
+ 4.4. Originator Fields ................................ 21
+ 4.5. Receiver Fields .................................. 23
+ 4.6. Reference Fields ................................. 23
+ 4.7. Other Fields ..................................... 24
+
+ 5. DATE AND TIME SPECIFICATION ............................ 26
+
+ 5.1. Syntax ........................................... 26
+ 5.2. Semantics ........................................ 26
+
+ 6. ADDRESS SPECIFICATION .................................. 27
+
+ 6.1. Syntax ........................................... 27
+ 6.2. Semantics ........................................ 27
+ 6.3. Reserved Address ................................. 33
+
+ 7. BIBLIOGRAPHY ........................................... 34
+
+
+ APPENDIX
+
+ A. EXAMPLES ............................................... 36
+ B. SIMPLE FIELD PARSING ................................... 40
+ C. DIFFERENCES FROM RFC #733 .............................. 41
+ D. ALPHABETICAL LISTING OF SYNTAX RULES ................... 44
+
+
+ August 13, 1982 - i - RFC #822
+
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ PREFACE
+
+
+ By 1977, the Arpanet employed several informal standards for
+ the text messages (mail) sent among its host computers. It was
+ felt necessary to codify these practices and provide for those
+ features that seemed imminent. The result of that effort was
+ Request for Comments (RFC) #733, "Standard for the Format of ARPA
+ Network Text Message", by Crocker, Vittal, Pogran, and Henderson.
+ The specification attempted to avoid major changes in existing
+ software, while permitting several new features.
+
+ This document revises the specifications in RFC #733, in
+ order to serve the needs of the larger and more complex ARPA
+ Internet. Some of RFC #733's features failed to gain adequate
+ acceptance. In order to simplify the standard and the software
+ that follows it, these features have been removed. A different
+ addressing scheme is used, to handle the case of inter-network
+ mail; and the concept of re-transmission has been introduced.
+
+ This specification is intended for use in the ARPA Internet.
+ However, an attempt has been made to free it of any dependence on
+ that environment, so that it can be applied to other network text
+ message systems.
+
+ The specification of RFC #733 took place over the course of
+ one year, using the ARPANET mail environment, itself, to provide
+ an on-going forum for discussing the capabilities to be included.
+ More than twenty individuals, from across the country, partici-
+ pated in the original discussion. The development of this
+ revised specification has, similarly, utilized network mail-based
+ group discussion. Both specification efforts greatly benefited
+ from the comments and ideas of the participants.
+
+ The syntax of the standard, in RFC #733, was originally
+ specified in the Backus-Naur Form (BNF) meta-language. Ken L.
+ Harrenstien, of SRI International, was responsible for re-coding
+ the BNF into an augmented BNF that makes the representation
+ smaller and easier to understand.
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - ii - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 1. INTRODUCTION
+
+ 1.1. SCOPE
+
+ This standard specifies a syntax for text messages that are
+ sent among computer users, within the framework of "electronic
+ mail". The standard supersedes the one specified in ARPANET
+ Request for Comments #733, "Standard for the Format of ARPA Net-
+ work Text Messages".
+
+ In this context, messages are viewed as having an envelope
+ and contents. The envelope contains whatever information is
+ needed to accomplish transmission and delivery. The contents
+ compose the object to be delivered to the recipient. This stan-
+ dard applies only to the format and some of the semantics of mes-
+ sage contents. It contains no specification of the information
+ in the envelope.
+
+ However, some message systems may use information from the
+ contents to create the envelope. It is intended that this stan-
+ dard facilitate the acquisition of such information by programs.
+
+ Some message systems may store messages in formats that
+ differ from the one specified in this standard. This specifica-
+ tion is intended strictly as a definition of what message content
+ format is to be passed BETWEEN hosts.
+
+ Note: This standard is NOT intended to dictate the internal for-
+ mats used by sites, the specific message system features
+ that they are expected to support, or any of the charac-
+ teristics of user interface programs that create or read
+ messages.
+
+ A distinction should be made between what the specification
+ REQUIRES and what it ALLOWS. Messages can be made complex and
+ rich with formally-structured components of information or can be
+ kept small and simple, with a minimum of such information. Also,
+ the standard simplifies the interpretation of differing visual
+ formats in messages; only the visual aspect of a message is
+ affected and not the interpretation of information within it.
+ Implementors may choose to retain such visual distinctions.
+
+ The formal definition is divided into four levels. The bot-
+ tom level describes the meta-notation used in this document. The
+ second level describes basic lexical analyzers that feed tokens
+ to higher-level parsers. Next is an overall specification for
+ messages; it permits distinguishing individual fields. Finally,
+ there is definition of the contents of several structured fields.
+
+
+
+ August 13, 1982 - 1 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 1.2. COMMUNICATION FRAMEWORK
+
+ Messages consist of lines of text. No special provisions
+ are made for encoding drawings, facsimile, speech, or structured
+ text. No significant consideration has been given to questions
+ of data compression or to transmission and storage efficiency,
+ and the standard tends to be free with the number of bits con-
+ sumed. For example, field names are specified as free text,
+ rather than special terse codes.
+
+ A general "memo" framework is used. That is, a message con-
+ sists of some information in a rigid format, followed by the main
+ part of the message, with a format that is not specified in this
+ document. The syntax of several fields of the rigidly-formated
+ ("headers") section is defined in this specification; some of
+ these fields must be included in all messages.
+
+ The syntax that distinguishes between header fields is
+ specified separately from the internal syntax for particular
+ fields. This separation is intended to allow simple parsers to
+ operate on the general structure of messages, without concern for
+ the detailed structure of individual header fields. Appendix B
+ is provided to facilitate construction of these parsers.
+
+ In addition to the fields specified in this document, it is
+ expected that other fields will gain common use. As necessary,
+ the specifications for these "extension-fields" will be published
+ through the same mechanism used to publish this document. Users
+ may also wish to extend the set of fields that they use
+ privately. Such "user-defined fields" are permitted.
+
+ The framework severely constrains document tone and appear-
+ ance and is primarily useful for most intra-organization communi-
+ cations and well-structured inter-organization communication.
+ It also can be used for some types of inter-process communica-
+ tion, such as simple file transfer and remote job entry. A more
+ robust framework might allow for multi-font, multi-color, multi-
+ dimension encoding of information. A less robust one, as is
+ present in most single-machine message systems, would more
+ severely constrain the ability to add fields and the decision to
+ include specific fields. In contrast with paper-based communica-
+ tion, it is interesting to note that the RECEIVER of a message
+ can exercise an extraordinary amount of control over the
+ message's appearance. The amount of actual control available to
+ message receivers is contingent upon the capabilities of their
+ individual message systems.
+
+
+
+
+
+ August 13, 1982 - 2 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 2. NOTATIONAL CONVENTIONS
+
+ This specification uses an augmented Backus-Naur Form (BNF)
+ notation. The differences from standard BNF involve naming rules
+ and indicating repetition and "local" alternatives.
+
+ 2.1. RULE NAMING
+
+ Angle brackets ("<", ">") are not used, in general. The
+ name of a rule is simply the name itself, rather than "<name>".
+ Quotation-marks enclose literal text (which may be upper and/or
+ lower case). Certain basic rules are in uppercase, such as
+ SPACE, TAB, CRLF, DIGIT, ALPHA, etc. Angle brackets are used in
+ rule definitions, and in the rest of this document, whenever
+ their presence will facilitate discerning the use of rule names.
+
+ 2.2. RULE1 / RULE2: ALTERNATIVES
+
+ Elements separated by slash ("/") are alternatives. There-
+ fore "foo / bar" will accept foo or bar.
+
+ 2.3. (RULE1 RULE2): LOCAL ALTERNATIVES
+
+ Elements enclosed in parentheses are treated as a single
+ element. Thus, "(elem (foo / bar) elem)" allows the token
+ sequences "elem foo elem" and "elem bar elem".
+
+ 2.4. *RULE: REPETITION
+
+ The character "*" preceding an element indicates repetition.
+ The full form is:
+
+ <l>*<m>element
+
+ indicating at least <l> and at most <m> occurrences of element.
+ Default values are 0 and infinity so that "*(element)" allows any
+ number, including zero; "1*element" requires at least one; and
+ "1*2element" allows one or two.
+
+ 2.5. [RULE]: OPTIONAL
+
+ Square brackets enclose optional elements; "[foo bar]" is
+ equivalent to "*1(foo bar)".
+
+ 2.6. NRULE: SPECIFIC REPETITION
+
+ "<n>(element)" is equivalent to "<n>*<n>(element)"; that is,
+ exactly <n> occurrences of (element). Thus 2DIGIT is a 2-digit
+ number, and 3ALPHA is a string of three alphabetic characters.
+
+
+ August 13, 1982 - 3 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 2.7. #RULE: LISTS
+
+ A construct "#" is defined, similar to "*", as follows:
+
+ <l>#<m>element
+
+ indicating at least <l> and at most <m> elements, each separated
+ by one or more commas (","). This makes the usual form of lists
+ very easy; a rule such as '(element *("," element))' can be shown
+ as "1#element". Wherever this construct is used, null elements
+ are allowed, but do not contribute to the count of elements
+ present. That is, "(element),,(element)" is permitted, but
+ counts as only two elements. Therefore, where at least one ele-
+ ment is required, at least one non-null element must be present.
+ Default values are 0 and infinity so that "#(element)" allows any
+ number, including zero; "1#element" requires at least one; and
+ "1#2element" allows one or two.
+
+ 2.8. ; COMMENTS
+
+ A semi-colon, set off some distance to the right of rule
+ text, starts a comment that continues to the end of line. This
+ is a simple way of including useful notes in parallel with the
+ specifications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 4 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 3. LEXICAL ANALYSIS OF MESSAGES
+
+ 3.1. GENERAL DESCRIPTION
+
+ A message consists of header fields and, optionally, a body.
+ The body is simply a sequence of lines containing ASCII charac-
+ ters. It is separated from the headers by a null line (i.e., a
+ line with nothing preceding the CRLF).
+
+ 3.1.1. LONG HEADER FIELDS
+
+ Each header field can be viewed as a single, logical line of
+ ASCII characters, comprising a field-name and a field-body.
+ For convenience, the field-body portion of this conceptual
+ entity can be split into a multiple-line representation; this
+ is called "folding". The general rule is that wherever there
+ may be linear-white-space (NOT simply LWSP-chars), a CRLF
+ immediately followed by AT LEAST one LWSP-char may instead be
+ inserted. Thus, the single line
+
+ To: "Joe & J. Harvey" <ddd @Org>, JJV @ BBN
+
+ can be represented as:
+
+ To: "Joe & J. Harvey" <ddd @ Org>,
+ JJV@BBN
+
+ and
+
+ To: "Joe & J. Harvey"
+ <ddd@ Org>, JJV
+ @BBN
+
+ and
+
+ To: "Joe &
+ J. Harvey" <ddd @ Org>, JJV @ BBN
+
+ The process of moving from this folded multiple-line
+ representation of a header field to its single line represen-
+ tation is called "unfolding". Unfolding is accomplished by
+ regarding CRLF immediately followed by a LWSP-char as
+ equivalent to the LWSP-char.
+
+ Note: While the standard permits folding wherever linear-
+ white-space is permitted, it is recommended that struc-
+ tured fields, such as those containing addresses, limit
+ folding to higher-level syntactic breaks. For address
+ fields, it is recommended that such folding occur
+
+
+ August 13, 1982 - 5 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ between addresses, after the separating comma.
+
+ 3.1.2. STRUCTURE OF HEADER FIELDS
+
+ Once a field has been unfolded, it may be viewed as being com-
+ posed of a field-name followed by a colon (":"), followed by a
+ field-body, and terminated by a carriage-return/line-feed.
+ The field-name must be composed of printable ASCII characters
+ (i.e., characters that have values between 33. and 126.,
+ decimal, except colon). The field-body may be composed of any
+ ASCII characters, except CR or LF. (While CR and/or LF may be
+ present in the actual text, they are removed by the action of
+ unfolding the field.)
+
+ Certain field-bodies of headers may be interpreted according
+ to an internal syntax that some systems may wish to parse.
+ These fields are called "structured fields". Examples
+ include fields containing dates and addresses. Other fields,
+ such as "Subject" and "Comments", are regarded simply as
+ strings of text.
+
+ Note: Any field which has a field-body that is defined as
+ other than simply <text> is to be treated as a struc-
+ tured field.
+
+ Field-names, unstructured field bodies and structured
+ field bodies each are scanned by their own, independent
+ "lexical" analyzers.
+
+ 3.1.3. UNSTRUCTURED FIELD BODIES
+
+ For some fields, such as "Subject" and "Comments", no struc-
+ turing is assumed, and they are treated simply as <text>s, as
+ in the message body. Rules of folding apply to these fields,
+ so that such field bodies which occupy several lines must
+ therefore have the second and successive lines indented by at
+ least one LWSP-char.
+
+ 3.1.4. STRUCTURED FIELD BODIES
+
+ To aid in the creation and reading of structured fields, the
+ free insertion of linear-white-space (which permits folding
+ by inclusion of CRLFs) is allowed between lexical tokens.
+ Rather than obscuring the syntax specifications for these
+ structured fields with explicit syntax for this linear-white-
+ space, the existence of another "lexical" analyzer is assumed.
+ This analyzer does not apply for unstructured field bodies
+ that are simply strings of text, as described above. The
+ analyzer provides an interpretation of the unfolded text
+
+
+ August 13, 1982 - 6 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ composing the body of the field as a sequence of lexical sym-
+ bols.
+
+ These symbols are:
+
+ - individual special characters
+ - quoted-strings
+ - domain-literals
+ - comments
+ - atoms
+
+ The first four of these symbols are self-delimiting. Atoms
+ are not; they are delimited by the self-delimiting symbols and
+ by linear-white-space. For the purposes of regenerating
+ sequences of atoms and quoted-strings, exactly one SPACE is
+ assumed to exist, and should be used, between them. (Also, in
+ the "Clarifications" section on "White Space", below, note the
+ rules about treatment of multiple contiguous LWSP-chars.)
+
+ So, for example, the folded body of an address field
+
+ ":sysmail"@ Some-Group. Some-Org,
+ Muhammed.(I am the greatest) Ali @(the)Vegas.WBA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 7 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ is analyzed into the following lexical symbols and types:
+
+ :sysmail quoted string
+ @ special
+ Some-Group atom
+ . special
+ Some-Org atom
+ , special
+ Muhammed atom
+ . special
+ (I am the greatest) comment
+ Ali atom
+ @ atom
+ (the) comment
+ Vegas atom
+ . special
+ WBA atom
+
+ The canonical representations for the data in these addresses
+ are the following strings:
+
+ ":sysmail"@Some-Group.Some-Org
+
+ and
+
+ Muhammed.Ali@Vegas.WBA
+
+ Note: For purposes of display, and when passing such struc-
+ tured information to other systems, such as mail proto-
+ col services, there must be NO linear-white-space
+ between <word>s that are separated by period (".") or
+ at-sign ("@") and exactly one SPACE between all other
+ <word>s. Also, headers should be in a folded form.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 8 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 3.2. HEADER FIELD DEFINITIONS
+
+ These rules show a field meta-syntax, without regard for the
+ particular type or internal syntax. Their purpose is to permit
+ detection of fields; also, they present to higher-level parsers
+ an image of each field as fitting on one line.
+
+ field = field-name ":" [ field-body ] CRLF
+
+ field-name = 1*<any CHAR, excluding CTLs, SPACE, and ":">
+
+ field-body = field-body-contents
+ [CRLF LWSP-char field-body]
+
+ field-body-contents =
+ <the ASCII characters making up the field-body, as
+ defined in the following sections, and consisting
+ of combinations of atom, quoted-string, and
+ specials tokens, or else consisting of texts>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 9 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 3.3. LEXICAL TOKENS
+
+ The following rules are used to define an underlying lexical
+ analyzer, which feeds tokens to higher level parsers. See the
+ ANSI references, in the Bibliography.
+
+ ; ( Octal, Decimal.)
+ CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
+ ALPHA = <any ASCII alphabetic character>
+ ; (101-132, 65.- 90.)
+ ; (141-172, 97.-122.)
+ DIGIT = <any ASCII decimal digit> ; ( 60- 71, 48.- 57.)
+ CTL = <any ASCII control ; ( 0- 37, 0.- 31.)
+ character and DEL> ; ( 177, 127.)
+ CR = <ASCII CR, carriage return> ; ( 15, 13.)
+ LF = <ASCII LF, linefeed> ; ( 12, 10.)
+ SPACE = <ASCII SP, space> ; ( 40, 32.)
+ HTAB = <ASCII HT, horizontal-tab> ; ( 11, 9.)
+ <"> = <ASCII quote mark> ; ( 42, 34.)
+ CRLF = CR LF
+
+ LWSP-char = SPACE / HTAB ; semantics = SPACE
+
+ linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE
+ ; CRLF => folding
+
+ specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted-
+ / "," / ";" / ":" / "\" / <"> ; string, to use
+ / "." / "[" / "]" ; within a word.
+
+ delimiters = specials / linear-white-space / comment
+
+ text = <any CHAR, including bare ; => atoms, specials,
+ CR & bare LF, but NOT ; comments and
+ including CRLF> ; quoted-strings are
+ ; NOT recognized.
+
+ atom = 1*<any CHAR except specials, SPACE and CTLs>
+
+ quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
+ ; quoted chars.
+
+ qtext = <any CHAR excepting <">, ; => may be folded
+ "\" & CR, and including
+ linear-white-space>
+
+ domain-literal = "[" *(dtext / quoted-pair) "]"
+
+
+
+
+ August 13, 1982 - 10 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ dtext = <any CHAR excluding "[", ; => may be folded
+ "]", "\" & CR, & including
+ linear-white-space>
+
+ comment = "(" *(ctext / quoted-pair / comment) ")"
+
+ ctext = <any CHAR excluding "(", ; => may be folded
+ ")", "\" & CR, & including
+ linear-white-space>
+
+ quoted-pair = "\" CHAR ; may quote any char
+
+ phrase = 1*word ; Sequence of words
+
+ word = atom / quoted-string
+
+
+ 3.4. CLARIFICATIONS
+
+ 3.4.1. QUOTING
+
+ Some characters are reserved for special interpretation, such
+ as delimiting lexical tokens. To permit use of these charac-
+ ters as uninterpreted data, a quoting mechanism is provided.
+ To quote a character, precede it with a backslash ("\").
+
+ This mechanism is not fully general. Characters may be quoted
+ only within a subset of the lexical constructs. In particu-
+ lar, quoting is limited to use within:
+
+ - quoted-string
+ - domain-literal
+ - comment
+
+ Within these constructs, quoting is REQUIRED for CR and "\"
+ and for the character(s) that delimit the token (e.g., "(" and
+ ")" for a comment). However, quoting is PERMITTED for any
+ character.
+
+ Note: In particular, quoting is NOT permitted within atoms.
+ For example when the local-part of an addr-spec must
+ contain a special character, a quoted string must be
+ used. Therefore, a specification such as:
+
+ Full\ Name@Domain
+
+ is not legal and must be specified as:
+
+ "Full Name"@Domain
+
+
+ August 13, 1982 - 11 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 3.4.2. WHITE SPACE
+
+ Note: In structured field bodies, multiple linear space ASCII
+ characters (namely HTABs and SPACEs) are treated as
+ single spaces and may freely surround any symbol. In
+ all header fields, the only place in which at least one
+ LWSP-char is REQUIRED is at the beginning of continua-
+ tion lines in a folded field.
+
+ When passing text to processes that do not interpret text
+ according to this standard (e.g., mail protocol servers), then
+ NO linear-white-space characters should occur between a period
+ (".") or at-sign ("@") and a <word>. Exactly ONE SPACE should
+ be used in place of arbitrary linear-white-space and comment
+ sequences.
+
+ Note: Within systems conforming to this standard, wherever a
+ member of the list of delimiters is allowed, LWSP-chars
+ may also occur before and/or after it.
+
+ Writers of mail-sending (i.e., header-generating) programs
+ should realize that there is no network-wide definition of the
+ effect of ASCII HT (horizontal-tab) characters on the appear-
+ ance of text at another network host; therefore, the use of
+ tabs in message headers, though permitted, is discouraged.
+
+ 3.4.3. COMMENTS
+
+ A comment is a set of ASCII characters, which is enclosed in
+ matching parentheses and which is not within a quoted-string
+ The comment construct permits message originators to add text
+ which will be useful for human readers, but which will be
+ ignored by the formal semantics. Comments should be retained
+ while the message is subject to interpretation according to
+ this standard. However, comments must NOT be included in
+ other cases, such as during protocol exchanges with mail
+ servers.
+
+ Comments nest, so that if an unquoted left parenthesis occurs
+ in a comment string, there must also be a matching right
+ parenthesis. When a comment acts as the delimiter between a
+ sequence of two lexical symbols, such as two atoms, it is lex-
+ ically equivalent with a single SPACE, for the purposes of
+ regenerating the sequence, such as when passing the sequence
+ onto a mail protocol server. Comments are detected as such
+ only within field-bodies of structured fields.
+
+ If a comment is to be "folded" onto multiple lines, then the
+ syntax for folding must be adhered to. (See the "Lexical
+
+
+ August 13, 1982 - 12 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ Analysis of Messages" section on "Folding Long Header Fields"
+ above, and the section on "Case Independence" below.) Note
+ that the official semantics therefore do not "see" any
+ unquoted CRLFs that are in comments, although particular pars-
+ ing programs may wish to note their presence. For these pro-
+ grams, it would be reasonable to interpret a "CRLF LWSP-char"
+ as being a CRLF that is part of the comment; i.e., the CRLF is
+ kept and the LWSP-char is discarded. Quoted CRLFs (i.e., a
+ backslash followed by a CR followed by a LF) still must be
+ followed by at least one LWSP-char.
+
+ 3.4.4. DELIMITING AND QUOTING CHARACTERS
+
+ The quote character (backslash) and characters that delimit
+ syntactic units are not, generally, to be taken as data that
+ are part of the delimited or quoted unit(s). In particular,
+ the quotation-marks that define a quoted-string, the
+ parentheses that define a comment and the backslash that
+ quotes a following character are NOT part of the quoted-
+ string, comment or quoted character. A quotation-mark that is
+ to be part of a quoted-string, a parenthesis that is to be
+ part of a comment and a backslash that is to be part of either
+ must each be preceded by the quote-character backslash ("\").
+ Note that the syntax allows any character to be quoted within
+ a quoted-string or comment; however only certain characters
+ MUST be quoted to be included as data. These characters are
+ the ones that are not part of the alternate text group (i.e.,
+ ctext or qtext).
+
+ The one exception to this rule is that a single SPACE is
+ assumed to exist between contiguous words in a phrase, and
+ this interpretation is independent of the actual number of
+ LWSP-chars that the creator places between the words. To
+ include more than one SPACE, the creator must make the LWSP-
+ chars be part of a quoted-string.
+
+ Quotation marks that delimit a quoted string and backslashes
+ that quote the following character should NOT accompany the
+ quoted-string when the string is passed to processes that do
+ not interpret data according to this specification (e.g., mail
+ protocol servers).
+
+ 3.4.5. QUOTED-STRINGS
+
+ Where permitted (i.e., in words in structured fields) quoted-
+ strings are treated as a single symbol. That is, a quoted-
+ string is equivalent to an atom, syntactically. If a quoted-
+ string is to be "folded" onto multiple lines, then the syntax
+ for folding must be adhered to. (See the "Lexical Analysis of
+
+
+ August 13, 1982 - 13 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ Messages" section on "Folding Long Header Fields" above, and
+ the section on "Case Independence" below.) Therefore, the
+ official semantics do not "see" any bare CRLFs that are in
+ quoted-strings; however particular parsing programs may wish
+ to note their presence. For such programs, it would be rea-
+ sonable to interpret a "CRLF LWSP-char" as being a CRLF which
+ is part of the quoted-string; i.e., the CRLF is kept and the
+ LWSP-char is discarded. Quoted CRLFs (i.e., a backslash fol-
+ lowed by a CR followed by a LF) are also subject to rules of
+ folding, but the presence of the quoting character (backslash)
+ explicitly indicates that the CRLF is data to the quoted
+ string. Stripping off the first following LWSP-char is also
+ appropriate when parsing quoted CRLFs.
+
+ 3.4.6. BRACKETING CHARACTERS
+
+ There is one type of bracket which must occur in matched pairs
+ and may have pairs nested within each other:
+
+ o Parentheses ("(" and ")") are used to indicate com-
+ ments.
+
+ There are three types of brackets which must occur in matched
+ pairs, and which may NOT be nested:
+
+ o Colon/semi-colon (":" and ";") are used in address
+ specifications to indicate that the included list of
+ addresses are to be treated as a group.
+
+ o Angle brackets ("<" and ">") are generally used to
+ indicate the presence of a one machine-usable refer-
+ ence (e.g., delimiting mailboxes), possibly including
+ source-routing to the machine.
+
+ o Square brackets ("[" and "]") are used to indicate the
+ presence of a domain-literal, which the appropriate
+ name-domain is to use directly, bypassing normal
+ name-resolution mechanisms.
+
+ 3.4.7. CASE INDEPENDENCE
+
+ Except as noted, alphabetic strings may be represented in any
+ combination of upper and lower case. The only syntactic units
+
+
+
+
+
+
+
+
+ August 13, 1982 - 14 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ which requires preservation of case information are:
+
+ - text
+ - qtext
+ - dtext
+ - ctext
+ - quoted-pair
+ - local-part, except "Postmaster"
+
+ When matching any other syntactic unit, case is to be ignored.
+ For example, the field-names "From", "FROM", "from", and even
+ "FroM" are semantically equal and should all be treated ident-
+ ically.
+
+ When generating these units, any mix of upper and lower case
+ alphabetic characters may be used. The case shown in this
+ specification is suggested for message-creating processes.
+
+ Note: The reserved local-part address unit, "Postmaster", is
+ an exception. When the value "Postmaster" is being
+ interpreted, it must be accepted in any mixture of
+ case, including "POSTMASTER", and "postmaster".
+
+ 3.4.8. FOLDING LONG HEADER FIELDS
+
+ Each header field may be represented on exactly one line con-
+ sisting of the name of the field and its body, and terminated
+ by a CRLF; this is what the parser sees. For readability, the
+ field-body portion of long header fields may be "folded" onto
+ multiple lines of the actual field. "Long" is commonly inter-
+ preted to mean greater than 65 or 72 characters. The former
+ length serves as a limit, when the message is to be viewed on
+ most simple terminals which use simple display software; how-
+ ever, the limit is not imposed by this standard.
+
+ Note: Some display software often can selectively fold lines,
+ to suit the display terminal. In such cases, sender-
+ provided folding can interfere with the display
+ software.
+
+ 3.4.9. BACKSPACE CHARACTERS
+
+ ASCII BS characters (Backspace, decimal 8) may be included in
+ texts and quoted-strings to effect overstriking. However, any
+ use of backspaces which effects an overstrike to the left of
+ the beginning of the text or quoted-string is prohibited.
+
+
+
+
+
+ August 13, 1982 - 15 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 3.4.10. NETWORK-SPECIFIC TRANSFORMATIONS
+
+ During transmission through heterogeneous networks, it may be
+ necessary to force data to conform to a network's local con-
+ ventions. For example, it may be required that a CR be fol-
+ lowed either by LF, making a CRLF, or by <null>, if the CR is
+ to stand alone). Such transformations are reversed, when the
+ message exits that network.
+
+ When crossing network boundaries, the message should be
+ treated as passing through two modules. It will enter the
+ first module containing whatever network-specific transforma-
+ tions that were necessary to permit migration through the
+ "current" network. It then passes through the modules:
+
+ o Transformation Reversal
+
+ The "current" network's idiosyncracies are removed and
+ the message is returned to the canonical form speci-
+ fied in this standard.
+
+ o Transformation
+
+ The "next" network's local idiosyncracies are imposed
+ on the message.
+
+ ------------------
+ From ==> | Remove Net-A |
+ Net-A | idiosyncracies |
+ ------------------
+ ||
+ \/
+ Conformance
+ with standard
+ ||
+ \/
+ ------------------
+ | Impose Net-B | ==> To
+ | idiosyncracies | Net-B
+ ------------------
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 16 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 4. MESSAGE SPECIFICATION
+
+ 4.1. SYNTAX
+
+ Note: Due to an artifact of the notational conventions, the syn-
+ tax indicates that, when present, some fields, must be in
+ a particular order. Header fields are NOT required to
+ occur in any particular order, except that the message
+ body must occur AFTER the headers. It is recommended
+ that, if present, headers be sent in the order "Return-
+ Path", "Received", "Date", "From", "Subject", "Sender",
+ "To", "cc", etc.
+
+ This specification permits multiple occurrences of most
+ fields. Except as noted, their interpretation is not
+ specified here, and their use is discouraged.
+
+ The following syntax for the bodies of various fields should
+ be thought of as describing each field body as a single long
+ string (or line). The "Lexical Analysis of Message" section on
+ "Long Header Fields", above, indicates how such long strings can
+ be represented on more than one line in the actual transmitted
+ message.
+
+ message = fields *( CRLF *text ) ; Everything after
+ ; first null line
+ ; is message body
+
+ fields = dates ; Creation time,
+ source ; author id & one
+ 1*destination ; address required
+ *optional-field ; others optional
+
+ source = [ trace ] ; net traversals
+ originator ; original mail
+ [ resent ] ; forwarded
+
+ trace = return ; path to sender
+ 1*received ; receipt tags
+
+ return = "Return-path" ":" route-addr ; return address
+
+ received = "Received" ":" ; one per relay
+ ["from" domain] ; sending host
+ ["by" domain] ; receiving host
+ ["via" atom] ; physical path
+ *("with" atom) ; link/mail protocol
+ ["id" msg-id] ; receiver msg id
+ ["for" addr-spec] ; initial form
+
+
+ August 13, 1982 - 17 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ ";" date-time ; time received
+
+ originator = authentic ; authenticated addr
+ [ "Reply-To" ":" 1#address] )
+
+ authentic = "From" ":" mailbox ; Single author
+ / ( "Sender" ":" mailbox ; Actual submittor
+ "From" ":" 1#mailbox) ; Multiple authors
+ ; or not sender
+
+ resent = resent-authentic
+ [ "Resent-Reply-To" ":" 1#address] )
+
+ resent-authentic =
+ = "Resent-From" ":" mailbox
+ / ( "Resent-Sender" ":" mailbox
+ "Resent-From" ":" 1#mailbox )
+
+ dates = orig-date ; Original
+ [ resent-date ] ; Forwarded
+
+ orig-date = "Date" ":" date-time
+
+ resent-date = "Resent-Date" ":" date-time
+
+ destination = "To" ":" 1#address ; Primary
+ / "Resent-To" ":" 1#address
+ / "cc" ":" 1#address ; Secondary
+ / "Resent-cc" ":" 1#address
+ / "bcc" ":" #address ; Blind carbon
+ / "Resent-bcc" ":" #address
+
+ optional-field =
+ / "Message-ID" ":" msg-id
+ / "Resent-Message-ID" ":" msg-id
+ / "In-Reply-To" ":" *(phrase / msg-id)
+ / "References" ":" *(phrase / msg-id)
+ / "Keywords" ":" #phrase
+ / "Subject" ":" *text
+ / "Comments" ":" *text
+ / "Encrypted" ":" 1#2word
+ / extension-field ; To be defined
+ / user-defined-field ; May be pre-empted
+
+ msg-id = "<" addr-spec ">" ; Unique message id
+
+
+
+
+
+
+ August 13, 1982 - 18 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ extension-field =
+ <Any field which is defined in a document
+ published as a formal extension to this
+ specification; none will have names beginning
+ with the string "X-">
+
+ user-defined-field =
+ <Any field which has not been defined
+ in this specification or published as an
+ extension to this specification; names for
+ such fields must be unique and may be
+ pre-empted by published extensions>
+
+ 4.2. FORWARDING
+
+ Some systems permit mail recipients to forward a message,
+ retaining the original headers, by adding some new fields. This
+ standard supports such a service, through the "Resent-" prefix to
+ field names.
+
+ Whenever the string "Resent-" begins a field name, the field
+ has the same semantics as a field whose name does not have the
+ prefix. However, the message is assumed to have been forwarded
+ by an original recipient who attached the "Resent-" field. This
+ new field is treated as being more recent than the equivalent,
+ original field. For example, the "Resent-From", indicates the
+ person that forwarded the message, whereas the "From" field indi-
+ cates the original author.
+
+ Use of such precedence information depends upon partici-
+ pants' communication needs. For example, this standard does not
+ dictate when a "Resent-From:" address should receive replies, in
+ lieu of sending them to the "From:" address.
+
+ Note: In general, the "Resent-" fields should be treated as con-
+ taining a set of information that is independent of the
+ set of original fields. Information for one set should
+ not automatically be taken from the other. The interpre-
+ tation of multiple "Resent-" fields, of the same type, is
+ undefined.
+
+ In the remainder of this specification, occurrence of legal
+ "Resent-" fields are treated identically with the occurrence of
+
+
+
+
+
+
+
+
+ August 13, 1982 - 19 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ fields whose names do not contain this prefix.
+
+ 4.3. TRACE FIELDS
+
+ Trace information is used to provide an audit trail of mes-
+ sage handling. In addition, it indicates a route back to the
+ sender of the message.
+
+ The list of known "via" and "with" values are registered
+ with the Network Information Center, SRI International, Menlo
+ Park, California.
+
+ 4.3.1. RETURN-PATH
+
+ This field is added by the final transport system that
+ delivers the message to its recipient. The field is intended
+ to contain definitive information about the address and route
+ back to the message's originator.
+
+ Note: The "Reply-To" field is added by the originator and
+ serves to direct replies, whereas the "Return-Path"
+ field is used to identify a path back to the origina-
+ tor.
+
+ While the syntax indicates that a route specification is
+ optional, every attempt should be made to provide that infor-
+ mation in this field.
+
+ 4.3.2. RECEIVED
+
+ A copy of this field is added by each transport service that
+ relays the message. The information in the field can be quite
+ useful for tracing transport problems.
+
+ The names of the sending and receiving hosts and time-of-
+ receipt may be specified. The "via" parameter may be used, to
+ indicate what physical mechanism the message was sent over,
+ such as Arpanet or Phonenet, and the "with" parameter may be
+ used to indicate the mail-, or connection-, level protocol
+ that was used, such as the SMTP mail protocol, or X.25 tran-
+ sport protocol.
+
+ Note: Several "with" parameters may be included, to fully
+ specify the set of protocols that were used.
+
+ Some transport services queue mail; the internal message iden-
+ tifier that is assigned to the message may be noted, using the
+ "id" parameter. When the sending host uses a destination
+ address specification that the receiving host reinterprets, by
+
+
+ August 13, 1982 - 20 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ expansion or transformation, the receiving host may wish to
+ record the original specification, using the "for" parameter.
+ For example, when a copy of mail is sent to the member of a
+ distribution list, this parameter may be used to record the
+ original address that was used to specify the list.
+
+ 4.4. ORIGINATOR FIELDS
+
+ The standard allows only a subset of the combinations possi-
+ ble with the From, Sender, Reply-To, Resent-From, Resent-Sender,
+ and Resent-Reply-To fields. The limitation is intentional.
+
+ 4.4.1. FROM / RESENT-FROM
+
+ This field contains the identity of the person(s) who wished
+ this message to be sent. The message-creation process should
+ default this field to be a single, authenticated machine
+ address, indicating the AGENT (person, system or process)
+ entering the message. If this is not done, the "Sender" field
+ MUST be present. If the "From" field IS defaulted this way,
+ the "Sender" field is optional and is redundant with the
+ "From" field. In all cases, addresses in the "From" field
+ must be machine-usable (addr-specs) and may not contain named
+ lists (groups).
+
+ 4.4.2. SENDER / RESENT-SENDER
+
+ This field contains the authenticated identity of the AGENT
+ (person, system or process) that sends the message. It is
+ intended for use when the sender is not the author of the mes-
+ sage, or to indicate who among a group of authors actually
+ sent the message. If the contents of the "Sender" field would
+ be completely redundant with the "From" field, then the
+ "Sender" field need not be present and its use is discouraged
+ (though still legal). In particular, the "Sender" field MUST
+ be present if it is NOT the same as the "From" Field.
+
+ The Sender mailbox specification includes a word sequence
+ which must correspond to a specific agent (i.e., a human user
+ or a computer program) rather than a standard address. This
+ indicates the expectation that the field will identify the
+ single AGENT (person, system, or process) responsible for
+ sending the mail and not simply include the name of a mailbox
+ from which the mail was sent. For example in the case of a
+ shared login name, the name, by itself, would not be adequate.
+ The local-part address unit, which refers to this agent, is
+ expected to be a computer system term, and not (for example) a
+ generalized person reference which can be used outside the
+ network text message context.
+
+
+ August 13, 1982 - 21 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ Since the critical function served by the "Sender" field is
+ identification of the agent responsible for sending mail and
+ since computer programs cannot be held accountable for their
+ behavior, it is strongly recommended that when a computer pro-
+ gram generates a message, the HUMAN who is responsible for
+ that program be referenced as part of the "Sender" field mail-
+ box specification.
+
+ 4.4.3. REPLY-TO / RESENT-REPLY-TO
+
+ This field provides a general mechanism for indicating any
+ mailbox(es) to which responses are to be sent. Three typical
+ uses for this feature can be distinguished. In the first
+ case, the author(s) may not have regular machine-based mail-
+ boxes and therefore wish(es) to indicate an alternate machine
+ address. In the second case, an author may wish additional
+ persons to be made aware of, or responsible for, replies. A
+ somewhat different use may be of some help to "text message
+ teleconferencing" groups equipped with automatic distribution
+ services: include the address of that service in the "Reply-
+ To" field of all messages submitted to the teleconference;
+ then participants can "reply" to conference submissions to
+ guarantee the correct distribution of any submission of their
+ own.
+
+ Note: The "Return-Path" field is added by the mail transport
+ service, at the time of final deliver. It is intended
+ to identify a path back to the orginator of the mes-
+ sage. The "Reply-To" field is added by the message
+ originator and is intended to direct replies.
+
+ 4.4.4. AUTOMATIC USE OF FROM / SENDER / REPLY-TO
+
+ For systems which automatically generate address lists for
+ replies to messages, the following recommendations are made:
+
+ o The "Sender" field mailbox should be sent notices of
+ any problems in transport or delivery of the original
+ messages. If there is no "Sender" field, then the
+ "From" field mailbox should be used.
+
+ o The "Sender" field mailbox should NEVER be used
+ automatically, in a recipient's reply message.
+
+ o If the "Reply-To" field exists, then the reply should
+ go to the addresses indicated in that field and not to
+ the address(es) indicated in the "From" field.
+
+
+
+
+ August 13, 1982 - 22 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ o If there is a "From" field, but no "Reply-To" field,
+ the reply should be sent to the address(es) indicated
+ in the "From" field.
+
+ Sometimes, a recipient may actually wish to communicate with
+ the person that initiated the message transfer. In such
+ cases, it is reasonable to use the "Sender" address.
+
+ This recommendation is intended only for automated use of
+ originator-fields and is not intended to suggest that replies
+ may not also be sent to other recipients of messages. It is
+ up to the respective mail-handling programs to decide what
+ additional facilities will be provided.
+
+ Examples are provided in Appendix A.
+
+ 4.5. RECEIVER FIELDS
+
+ 4.5.1. TO / RESENT-TO
+
+ This field contains the identity of the primary recipients of
+ the message.
+
+ 4.5.2. CC / RESENT-CC
+
+ This field contains the identity of the secondary (informa-
+ tional) recipients of the message.
+
+ 4.5.3. BCC / RESENT-BCC
+
+ This field contains the identity of additional recipients of
+ the message. The contents of this field are not included in
+ copies of the message sent to the primary and secondary reci-
+ pients. Some systems may choose to include the text of the
+ "Bcc" field only in the author(s)'s copy, while others may
+ also include it in the text sent to all those indicated in the
+ "Bcc" list.
+
+ 4.6. REFERENCE FIELDS
+
+ 4.6.1. MESSAGE-ID / RESENT-MESSAGE-ID
+
+ This field contains a unique identifier (the local-part
+ address unit) which refers to THIS version of THIS message.
+ The uniqueness of the message identifier is guaranteed by the
+ host which generates it. This identifier is intended to be
+ machine readable and not necessarily meaningful to humans. A
+ message identifier pertains to exactly one instantiation of a
+ particular message; subsequent revisions to the message should
+
+
+ August 13, 1982 - 23 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ each receive new message identifiers.
+
+ 4.6.2. IN-REPLY-TO
+
+ The contents of this field identify previous correspon-
+ dence which this message answers. Note that if message iden-
+ tifiers are used in this field, they must use the msg-id
+ specification format.
+
+ 4.6.3. REFERENCES
+
+ The contents of this field identify other correspondence
+ which this message references. Note that if message identif-
+ iers are used, they must use the msg-id specification format.
+
+ 4.6.4. KEYWORDS
+
+ This field contains keywords or phrases, separated by
+ commas.
+
+ 4.7. OTHER FIELDS
+
+ 4.7.1. SUBJECT
+
+ This is intended to provide a summary, or indicate the
+ nature, of the message.
+
+ 4.7.2. COMMENTS
+
+ Permits adding text comments onto the message without
+ disturbing the contents of the message's body.
+
+ 4.7.3. ENCRYPTED
+
+ Sometimes, data encryption is used to increase the
+ privacy of message contents. If the body of a message has
+ been encrypted, to keep its contents private, the "Encrypted"
+ field can be used to note the fact and to indicate the nature
+ of the encryption. The first <word> parameter indicates the
+ software used to encrypt the body, and the second, optional
+ <word> is intended to aid the recipient in selecting the
+ proper decryption key. This code word may be viewed as an
+ index to a table of keys held by the recipient.
+
+ Note: Unfortunately, headers must contain envelope, as well
+ as contents, information. Consequently, it is neces-
+ sary that they remain unencrypted, so that mail tran-
+ sport services may access them. Since names,
+ addresses, and "Subject" field contents may contain
+
+
+ August 13, 1982 - 24 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ sensitive information, this requirement limits total
+ message privacy.
+
+ Names of encryption software are registered with the Net-
+ work Information Center, SRI International, Menlo Park, Cali-
+ fornia.
+
+ 4.7.4. EXTENSION-FIELD
+
+ A limited number of common fields have been defined in
+ this document. As network mail requirements dictate, addi-
+ tional fields may be standardized. To provide user-defined
+ fields with a measure of safety, in name selection, such
+ extension-fields will never have names that begin with the
+ string "X-".
+
+ Names of Extension-fields are registered with the Network
+ Information Center, SRI International, Menlo Park, California.
+
+ 4.7.5. USER-DEFINED-FIELD
+
+ Individual users of network mail are free to define and
+ use additional header fields. Such fields must have names
+ which are not already used in the current specification or in
+ any definitions of extension-fields, and the overall syntax of
+ these user-defined-fields must conform to this specification's
+ rules for delimiting and folding fields. Due to the
+ extension-field publishing process, the name of a user-
+ defined-field may be pre-empted
+
+ Note: The prefatory string "X-" will never be used in the
+ names of Extension-fields. This provides user-defined
+ fields with a protected set of names.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 25 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 5. DATE AND TIME SPECIFICATION
+
+ 5.1. SYNTAX
+
+ date-time = [ day "," ] date time ; dd mm yy
+ ; hh:mm:ss zzz
+
+ day = "Mon" / "Tue" / "Wed" / "Thu"
+ / "Fri" / "Sat" / "Sun"
+
+ date = 1*2DIGIT month 2DIGIT ; day month year
+ ; e.g. 20 Jun 82
+
+ month = "Jan" / "Feb" / "Mar" / "Apr"
+ / "May" / "Jun" / "Jul" / "Aug"
+ / "Sep" / "Oct" / "Nov" / "Dec"
+
+ time = hour zone ; ANSI and Military
+
+ hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
+ ; 00:00:00 - 23:59:59
+
+ zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ ; A:-1; (J not used)
+ ; M:-12; N:+1; Y:+12
+ / ( ("+" / "-") 4DIGIT ) ; Local differential
+ ; hours+min. (HHMM)
+
+ 5.2. SEMANTICS
+
+ If included, day-of-week must be the day implied by the date
+ specification.
+
+ Time zone may be indicated in several ways. "UT" is Univer-
+ sal Time (formerly called "Greenwich Mean Time"); "GMT" is per-
+ mitted as a reference to Universal Time. The military standard
+ uses a single character for each zone. "Z" is Universal Time.
+ "A" indicates one hour earlier, and "M" indicates 12 hours ear-
+ lier; "N" is one hour later, and "Y" is 12 hours later. The
+ letter "J" is not used. The other remaining two forms are taken
+ from ANSI standard X3.51-1975. One allows explicit indication of
+ the amount of offset from UT; the other uses common 3-character
+ strings for indicating time zones in North America.
+
+
+ August 13, 1982 - 26 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 6. ADDRESS SPECIFICATION
+
+ 6.1. SYNTAX
+
+ address = mailbox ; one addressee
+ / group ; named list
+
+ group = phrase ":" [#mailbox] ";"
+
+ mailbox = addr-spec ; simple address
+ / phrase route-addr ; name & addr-spec
+
+ route-addr = "<" [route] addr-spec ">"
+
+ route = 1#("@" domain) ":" ; path-relative
+
+ addr-spec = local-part "@" domain ; global address
+
+ local-part = word *("." word) ; uninterpreted
+ ; case-preserved
+
+ domain = sub-domain *("." sub-domain)
+
+ sub-domain = domain-ref / domain-literal
+
+ domain-ref = atom ; symbolic reference
+
+ 6.2. SEMANTICS
+
+ A mailbox receives mail. It is a conceptual entity which
+ does not necessarily pertain to file storage. For example, some
+ sites may choose to print mail on their line printer and deliver
+ the output to the addressee's desk.
+
+ A mailbox specification comprises a person, system or pro-
+ cess name reference, a domain-dependent string, and a name-domain
+ reference. The name reference is optional and is usually used to
+ indicate the human name of a recipient. The name-domain refer-
+ ence specifies a sequence of sub-domains. The domain-dependent
+ string is uninterpreted, except by the final sub-domain; the rest
+ of the mail service merely transmits it as a literal string.
+
+ 6.2.1. DOMAINS
+
+ A name-domain is a set of registered (mail) names. A name-
+ domain specification resolves to a subordinate name-domain
+ specification or to a terminal domain-dependent string.
+ Hence, domain specification is extensible, permitting any
+ number of registration levels.
+
+
+ August 13, 1982 - 27 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ Name-domains model a global, logical, hierarchical addressing
+ scheme. The model is logical, in that an address specifica-
+ tion is related to name registration and is not necessarily
+ tied to transmission path. The model's hierarchy is a
+ directed graph, called an in-tree, such that there is a single
+ path from the root of the tree to any node in the hierarchy.
+ If more than one path actually exists, they are considered to
+ be different addresses.
+
+ The root node is common to all addresses; consequently, it is
+ not referenced. Its children constitute "top-level" name-
+ domains. Usually, a service has access to its own full domain
+ specification and to the names of all top-level name-domains.
+
+ The "top" of the domain addressing hierarchy -- a child of the
+ root -- is indicated by the right-most field, in a domain
+ specification. Its child is specified to the left, its child
+ to the left, and so on.
+
+ Some groups provide formal registration services; these con-
+ stitute name-domains that are independent logically of
+ specific machines. In addition, networks and machines impli-
+ citly compose name-domains, since their membership usually is
+ registered in name tables.
+
+ In the case of formal registration, an organization implements
+ a (distributed) data base which provides an address-to-route
+ mapping service for addresses of the form:
+
+ person@registry.organization
+
+ Note that "organization" is a logical entity, separate from
+ any particular communication network.
+
+ A mechanism for accessing "organization" is universally avail-
+ able. That mechanism, in turn, seeks an instantiation of the
+ registry; its location is not indicated in the address specif-
+ ication. It is assumed that the system which operates under
+ the name "organization" knows how to find a subordinate regis-
+ try. The registry will then use the "person" string to deter-
+ mine where to send the mail specification.
+
+ The latter, network-oriented case permits simple, direct,
+ attachment-related address specification, such as:
+
+ user@host.network
+
+ Once the network is accessed, it is expected that a message
+ will go directly to the host and that the host will resolve
+
+
+ August 13, 1982 - 28 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ the user name, placing the message in the user's mailbox.
+
+ 6.2.2. ABBREVIATED DOMAIN SPECIFICATION
+
+ Since any number of levels is possible within the domain
+ hierarchy, specification of a fully qualified address can
+ become inconvenient. This standard permits abbreviated domain
+ specification, in a special case:
+
+ For the address of the sender, call the left-most
+ sub-domain Level N. In a header address, if all of
+ the sub-domains above (i.e., to the right of) Level N
+ are the same as those of the sender, then they do not
+ have to appear in the specification. Otherwise, the
+ address must be fully qualified.
+
+ This feature is subject to approval by local sub-
+ domains. Individual sub-domains may require their
+ member systems, which originate mail, to provide full
+ domain specification only. When permitted, abbrevia-
+ tions may be present only while the message stays
+ within the sub-domain of the sender.
+
+ Use of this mechanism requires the sender's sub-domain
+ to reserve the names of all top-level domains, so that
+ full specifications can be distinguished from abbrevi-
+ ated specifications.
+
+ For example, if a sender's address is:
+
+ sender@registry-A.registry-1.organization-X
+
+ and one recipient's address is:
+
+ recipient@registry-B.registry-1.organization-X
+
+ and another's is:
+
+ recipient@registry-C.registry-2.organization-X
+
+ then ".registry-1.organization-X" need not be specified in the
+ the message, but "registry-C.registry-2" DOES have to be
+ specified. That is, the first two addresses may be abbrevi-
+ ated, but the third address must be fully specified.
+
+ When a message crosses a domain boundary, all addresses must
+ be specified in the full format, ending with the top-level
+ name-domain in the right-most field. It is the responsibility
+ of mail forwarding services to ensure that addresses conform
+
+
+ August 13, 1982 - 29 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ with this requirement. In the case of abbreviated addresses,
+ the relaying service must make the necessary expansions. It
+ should be noted that it often is difficult for such a service
+ to locate all occurrences of address abbreviations. For exam-
+ ple, it will not be possible to find such abbreviations within
+ the body of the message. The "Return-Path" field can aid
+ recipients in recovering from these errors.
+
+ Note: When passing any portion of an addr-spec onto a process
+ which does not interpret data according to this stan-
+ dard (e.g., mail protocol servers). There must be NO
+ LWSP-chars preceding or following the at-sign or any
+ delimiting period ("."), such as shown in the above
+ examples, and only ONE SPACE between contiguous
+ <word>s.
+
+ 6.2.3. DOMAIN TERMS
+
+ A domain-ref must be THE official name of a registry, network,
+ or host. It is a symbolic reference, within a name sub-
+ domain. At times, it is necessary to bypass standard mechan-
+ isms for resolving such references, using more primitive
+ information, such as a network host address rather than its
+ associated host name.
+
+ To permit such references, this standard provides the domain-
+ literal construct. Its contents must conform with the needs
+ of the sub-domain in which it is interpreted.
+
+ Domain-literals which refer to domains within the ARPA Inter-
+ net specify 32-bit Internet addresses, in four 8-bit fields
+ noted in decimal, as described in Request for Comments #820,
+ "Assigned Numbers." For example:
+
+ [10.0.3.19]
+
+ Note: THE USE OF DOMAIN-LITERALS IS STRONGLY DISCOURAGED. It
+ is permitted only as a means of bypassing temporary
+ system limitations, such as name tables which are not
+ complete.
+
+ The names of "top-level" domains, and the names of domains
+ under in the ARPA Internet, are registered with the Network
+ Information Center, SRI International, Menlo Park, California.
+
+ 6.2.4. DOMAIN-DEPENDENT LOCAL STRING
+
+ The local-part of an addr-spec in a mailbox specification
+ (i.e., the host's name for the mailbox) is understood to be
+
+
+ August 13, 1982 - 30 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ whatever the receiving mail protocol server allows. For exam-
+ ple, some systems do not understand mailbox references of the
+ form "P. D. Q. Bach", but others do.
+
+ This specification treats periods (".") as lexical separators.
+ Hence, their presence in local-parts which are not quoted-
+ strings, is detected. However, such occurrences carry NO
+ semantics. That is, if a local-part has periods within it, an
+ address parser will divide the local-part into several tokens,
+ but the sequence of tokens will be treated as one uninter-
+ preted unit. The sequence will be re-assembled, when the
+ address is passed outside of the system such as to a mail pro-
+ tocol service.
+
+ For example, the address:
+
+ First.Last@Registry.Org
+
+ is legal and does not require the local-part to be surrounded
+ with quotation-marks. (However, "First Last" DOES require
+ quoting.) The local-part of the address, when passed outside
+ of the mail system, within the Registry.Org domain, is
+ "First.Last", again without quotation marks.
+
+ 6.2.5. BALANCING LOCAL-PART AND DOMAIN
+
+ In some cases, the boundary between local-part and domain can
+ be flexible. The local-part may be a simple string, which is
+ used for the final determination of the recipient's mailbox.
+ All other levels of reference are, therefore, part of the
+ domain.
+
+ For some systems, in the case of abbreviated reference to the
+ local and subordinate sub-domains, it may be possible to
+ specify only one reference within the domain part and place
+ the other, subordinate name-domain references within the
+ local-part. This would appear as:
+
+ mailbox.sub1.sub2@this-domain
+
+ Such a specification would be acceptable to address parsers
+ which conform to RFC #733, but do not support this newer
+ Internet standard. While contrary to the intent of this stan-
+ dard, the form is legal.
+
+ Also, some sub-domains have a specification syntax which does
+ not conform to this standard. For example:
+
+ sub-net.mailbox@sub-domain.domain
+
+
+ August 13, 1982 - 31 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ uses a different parsing sequence for local-part than for
+ domain.
+
+ Note: As a rule, the domain specification should contain
+ fields which are encoded according to the syntax of
+ this standard and which contain generally-standardized
+ information. The local-part specification should con-
+ tain only that portion of the address which deviates
+ from the form or intention of the domain field.
+
+ 6.2.6. MULTIPLE MAILBOXES
+
+ An individual may have several mailboxes and wish to receive
+ mail at whatever mailbox is convenient for the sender to
+ access. This standard does not provide a means of specifying
+ "any member of" a list of mailboxes.
+
+ A set of individuals may wish to receive mail as a single unit
+ (i.e., a distribution list). The <group> construct permits
+ specification of such a list. Recipient mailboxes are speci-
+ fied within the bracketed part (":" - ";"). A copy of the
+ transmitted message is to be sent to each mailbox listed.
+ This standard does not permit recursive specification of
+ groups within groups.
+
+ While a list must be named, it is not required that the con-
+ tents of the list be included. In this case, the <address>
+ serves only as an indication of group distribution and would
+ appear in the form:
+
+ name:;
+
+ Some mail services may provide a group-list distribution
+ facility, accepting a single mailbox reference, expanding it
+ to the full distribution list, and relaying the mail to the
+ list's members. This standard provides no additional syntax
+ for indicating such a service. Using the <group> address
+ alternative, while listing one mailbox in it, can mean either
+ that the mailbox reference will be expanded to a list or that
+ there is a group with one member.
+
+ 6.2.7. EXPLICIT PATH SPECIFICATION
+
+ At times, a message originator may wish to indicate the
+ transmission path that a message should follow. This is
+ called source routing. The normal addressing scheme, used in
+ an addr-spec, is carefully separated from such information;
+ the <route> portion of a route-addr is provided for such occa-
+ sions. It specifies the sequence of hosts and/or transmission
+
+
+ August 13, 1982 - 32 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ services that are to be traversed. Both domain-refs and
+ domain-literals may be used.
+
+ Note: The use of source routing is discouraged. Unless the
+ sender has special need of path restriction, the choice
+ of transmission route should be left to the mail tran-
+ sport service.
+
+ 6.3. RESERVED ADDRESS
+
+ It often is necessary to send mail to a site, without know-
+ ing any of its valid addresses. For example, there may be mail
+ system dysfunctions, or a user may wish to find out a person's
+ correct address, at that site.
+
+ This standard specifies a single, reserved mailbox address
+ (local-part) which is to be valid at each site. Mail sent to
+ that address is to be routed to a person responsible for the
+ site's mail system or to a person with responsibility for general
+ site operation. The name of the reserved local-part address is:
+
+ Postmaster
+
+ so that "Postmaster@domain" is required to be valid.
+
+ Note: This reserved local-part must be matched without sensi-
+ tivity to alphabetic case, so that "POSTMASTER", "postmas-
+ ter", and even "poStmASteR" is to be accepted.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 33 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ 7. BIBLIOGRAPHY
+
+
+ ANSI. "USA Standard Code for Information Interchange," X3.4.
+ American National Standards Institute: New York (1968). Also
+ in: Feinler, E. and J. Postel, eds., "ARPANET Protocol Hand-
+ book", NIC 7104.
+
+ ANSI. "Representations of Universal Time, Local Time Differen-
+ tials, and United States Time Zone References for Information
+ Interchange," X3.51-1975. American National Standards Insti-
+ tute: New York (1975).
+
+ Bemer, R.W., "Time and the Computer." In: Interface Age (Feb.
+ 1979).
+
+ Bennett, C.J. "JNT Mail Protocol". Joint Network Team, Ruther-
+ ford and Appleton Laboratory: Didcot, England.
+
+ Bhushan, A.K., Pogran, K.T., Tomlinson, R.S., and White, J.E.
+ "Standardizing Network Mail Headers," ARPANET Request for
+ Comments No. 561, Network Information Center No. 18516; SRI
+ International: Menlo Park (September 1973).
+
+ Birrell, A.D., Levin, R., Needham, R.M., and Schroeder, M.D.
+ "Grapevine: An Exercise in Distributed Computing," Communica-
+ tions of the ACM 25, 4 (April 1982), 260-274.
+
+ Crocker, D.H., Vittal, J.J., Pogran, K.T., Henderson, D.A.
+ "Standard for the Format of ARPA Network Text Message,"
+ ARPANET Request for Comments No. 733, Network Information
+ Center No. 41952. SRI International: Menlo Park (November
+ 1977).
+
+ Feinler, E.J. and Postel, J.B. ARPANET Protocol Handbook, Net-
+ work Information Center No. 7104 (NTIS AD A003890). SRI
+ International: Menlo Park (April 1976).
+
+ Harary, F. "Graph Theory". Addison-Wesley: Reading, Mass.
+ (1969).
+
+ Levin, R. and Schroeder, M. "Transport of Electronic Messages
+ through a Network," TeleInformatics 79, pp. 29-33. North
+ Holland (1979). Also as Xerox Palo Alto Research Center
+ Technical Report CSL-79-4.
+
+ Myer, T.H. and Henderson, D.A. "Message Transmission Protocol,"
+ ARPANET Request for Comments, No. 680, Network Information
+ Center No. 32116. SRI International: Menlo Park (1975).
+
+
+ August 13, 1982 - 34 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ NBS. "Specification of Message Format for Computer Based Message
+ Systems, Recommended Federal Information Processing Standard."
+ National Bureau of Standards: Gaithersburg, Maryland
+ (October 1981).
+
+ NIC. Internet Protocol Transition Workbook. Network Information
+ Center, SRI-International, Menlo Park, California (March
+ 1982).
+
+ Oppen, D.C. and Dalal, Y.K. "The Clearinghouse: A Decentralized
+ Agent for Locating Named Objects in a Distributed Environ-
+ ment," OPD-T8103. Xerox Office Products Division: Palo Alto,
+ CA. (October 1981).
+
+ Postel, J.B. "Assigned Numbers," ARPANET Request for Comments,
+ No. 820. SRI International: Menlo Park (August 1982).
+
+ Postel, J.B. "Simple Mail Transfer Protocol," ARPANET Request
+ for Comments, No. 821. SRI International: Menlo Park (August
+ 1982).
+
+ Shoch, J.F. "Internetwork naming, addressing and routing," in
+ Proc. 17th IEEE Computer Society International Conference, pp.
+ 72-79, Sept. 1978, IEEE Cat. No. 78 CH 1388-8C.
+
+ Su, Z. and Postel, J. "The Domain Naming Convention for Internet
+ User Applications," ARPANET Request for Comments, No. 819.
+ SRI International: Menlo Park (August 1982).
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 35 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ APPENDIX
+
+
+ A. EXAMPLES
+
+ A.1. ADDRESSES
+
+ A.1.1. Alfred Neuman <Neuman@BBN-TENEXA>
+
+ A.1.2. Neuman@BBN-TENEXA
+
+ These two "Alfred Neuman" examples have identical seman-
+ tics, as far as the operation of the local host's mail sending
+ (distribution) program (also sometimes called its "mailer")
+ and the remote host's mail protocol server are concerned. In
+ the first example, the "Alfred Neuman" is ignored by the
+ mailer, as "Neuman@BBN-TENEXA" completely specifies the reci-
+ pient. The second example contains no superfluous informa-
+ tion, and, again, "Neuman@BBN-TENEXA" is the intended reci-
+ pient.
+
+ Note: When the message crosses name-domain boundaries, then
+ these specifications must be changed, so as to indicate
+ the remainder of the hierarchy, starting with the top
+ level.
+
+ A.1.3. "George, Ted" <Shared@Group.Arpanet>
+
+ This form might be used to indicate that a single mailbox
+ is shared by several users. The quoted string is ignored by
+ the originating host's mailer, because "Shared@Group.Arpanet"
+ completely specifies the destination mailbox.
+
+ A.1.4. Wilt . (the Stilt) Chamberlain@NBA.US
+
+ The "(the Stilt)" is a comment, which is NOT included in
+ the destination mailbox address handed to the originating
+ system's mailer. The local-part of the address is the string
+ "Wilt.Chamberlain", with NO space between the first and second
+ words.
+
+ A.1.5. Address Lists
+
+ Gourmets: Pompous Person <WhoZiWhatZit@Cordon-Bleu>,
+ Childs@WGBH.Boston, Galloping Gourmet@
+ ANT.Down-Under (Australian National Television),
+ Cheapie@Discount-Liquors;,
+ Cruisers: Port@Portugal, Jones@SEA;,
+ Another@Somewhere.SomeOrg
+
+
+ August 13, 1982 - 36 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ This group list example points out the use of comments and the
+ mixing of addresses and groups.
+
+ A.2. ORIGINATOR ITEMS
+
+ A.2.1. Author-sent
+
+ George Jones logs into his host as "Jones". He sends
+ mail himself.
+
+ From: Jones@Group.Org
+
+ or
+
+ From: George Jones <Jones@Group.Org>
+
+ A.2.2. Secretary-sent
+
+ George Jones logs in as Jones on his host. His secre-
+ tary, who logs in as Secy sends mail for him. Replies to the
+ mail should go to George.
+
+ From: George Jones <Jones@Group>
+ Sender: Secy@Other-Group
+
+ A.2.3. Secretary-sent, for user of shared directory
+
+ George Jones' secretary sends mail for George. Replies
+ should go to George.
+
+ From: George Jones<Shared@Group.Org>
+ Sender: Secy@Other-Group
+
+ Note that there need not be a space between "Jones" and the
+ "<", but adding a space enhances readability (as is the case
+ in other examples.
+
+ A.2.4. Committee activity, with one author
+
+ George is a member of a committee. He wishes to have any
+ replies to his message go to all committee members.
+
+ From: George Jones <Jones@Host.Net>
+ Sender: Jones@Host
+ Reply-To: The Committee: Jones@Host.Net,
+ Smith@Other.Org,
+ Doe@Somewhere-Else;
+
+ Note that if George had not included himself in the
+
+
+ August 13, 1982 - 37 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ enumeration of The Committee, he would not have gotten an
+ implicit reply; the presence of the "Reply-to" field SUPER-
+ SEDES the sending of a reply to the person named in the "From"
+ field.
+
+ A.2.5. Secretary acting as full agent of author
+
+ George Jones asks his secretary (Secy@Host) to send a
+ message for him in his capacity as Group. He wants his secre-
+ tary to handle all replies.
+
+ From: George Jones <Group@Host>
+ Sender: Secy@Host
+ Reply-To: Secy@Host
+
+ A.2.6. Agent for user without online mailbox
+
+ A friend of George's, Sarah, is visiting. George's
+ secretary sends some mail to a friend of Sarah in computer-
+ land. Replies should go to George, whose mailbox is Jones at
+ Registry.
+
+ From: Sarah Friendly <Secy@Registry>
+ Sender: Secy-Name <Secy@Registry>
+ Reply-To: Jones@Registry.
+
+ A.2.7. Agent for member of a committee
+
+ George's secretary sends out a message which was authored
+ jointly by all the members of a committee. Note that the name
+ of the committee cannot be specified, since <group> names are
+ not permitted in the From field.
+
+ From: Jones@Host,
+ Smith@Other-Host,
+ Doe@Somewhere-Else
+ Sender: Secy@SHost
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 38 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ A.3. COMPLETE HEADERS
+
+ A.3.1. Minimum required
+
+ Date: 26 Aug 76 1429 EDT Date: 26 Aug 76 1429 EDT
+ From: Jones@Registry.Org or From: Jones@Registry.Org
+ Bcc: To: Smith@Registry.Org
+
+ Note that the "Bcc" field may be empty, while the "To" field
+ is required to have at least one address.
+
+ A.3.2. Using some of the additional fields
+
+ Date: 26 Aug 76 1430 EDT
+ From: George Jones<Group@Host>
+ Sender: Secy@SHOST
+ To: "Al Neuman"@Mad-Host,
+ Sam.Irving@Other-Host
+ Message-ID: <some.string@SHOST>
+
+ A.3.3. About as complex as you're going to get
+
+ Date : 27 Aug 76 0932 PDT
+ From : Ken Davis <KDavis@This-Host.This-net>
+ Subject : Re: The Syntax in the RFC
+ Sender : KSecy@Other-Host
+ Reply-To : Sam.Irving@Reg.Organization
+ To : George Jones <Group@Some-Reg.An-Org>,
+ Al.Neuman@MAD.Publisher
+ cc : Important folk:
+ Tom Softwood <Balsa@Tree.Root>,
+ "Sam Irving"@Other-Host;,
+ Standard Distribution:
+ /main/davis/people/standard@Other-Host,
+ "<Jones>standard.dist.3"@Tops-20-Host>;
+ Comment : Sam is away on business. He asked me to handle
+ his mail for him. He'll be able to provide a
+ more accurate explanation when he returns
+ next week.
+ In-Reply-To: <some.string@DBM.Group>, George's message
+ X-Special-action: This is a sample of user-defined field-
+ names. There could also be a field-name
+ "Special-action", but its name might later be
+ preempted
+ Message-ID: <4231.629.XYzi-What@Other-Host>
+
+
+
+
+
+
+ August 13, 1982 - 39 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ B. SIMPLE FIELD PARSING
+
+ Some mail-reading software systems may wish to perform only
+ minimal processing, ignoring the internal syntax of structured
+ field-bodies and treating them the same as unstructured-field-
+ bodies. Such software will need only to distinguish:
+
+ o Header fields from the message body,
+
+ o Beginnings of fields from lines which continue fields,
+
+ o Field-names from field-contents.
+
+ The abbreviated set of syntactic rules which follows will
+ suffice for this purpose. It describes a limited view of mes-
+ sages and is a subset of the syntactic rules provided in the main
+ part of this specification. One small exception is that the con-
+ tents of field-bodies consist only of text:
+
+ B.1. SYNTAX
+
+
+ message = *field *(CRLF *text)
+
+ field = field-name ":" [field-body] CRLF
+
+ field-name = 1*<any CHAR, excluding CTLs, SPACE, and ":">
+
+ field-body = *text [CRLF LWSP-char field-body]
+
+
+ B.2. SEMANTICS
+
+ Headers occur before the message body and are terminated by
+ a null line (i.e., two contiguous CRLFs).
+
+ A line which continues a header field begins with a SPACE or
+ HTAB character, while a line beginning a field starts with a
+ printable character which is not a colon.
+
+ A field-name consists of one or more printable characters
+ (excluding colon, space, and control-characters). A field-name
+ MUST be contained on one line. Upper and lower case are not dis-
+ tinguished when comparing field-names.
+
+
+
+
+
+
+
+ August 13, 1982 - 40 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ C. DIFFERENCES FROM RFC #733
+
+ The following summarizes the differences between this stan-
+ dard and the one specified in Arpanet Request for Comments #733,
+ "Standard for the Format of ARPA Network Text Messages". The
+ differences are listed in the order of their occurrence in the
+ current specification.
+
+ C.1. FIELD DEFINITIONS
+
+ C.1.1. FIELD NAMES
+
+ These now must be a sequence of printable characters. They
+ may not contain any LWSP-chars.
+
+ C.2. LEXICAL TOKENS
+
+ C.2.1. SPECIALS
+
+ The characters period ("."), left-square bracket ("["), and
+ right-square bracket ("]") have been added. For presentation
+ purposes, and when passing a specification to a system that
+ does not conform to this standard, periods are to be contigu-
+ ous with their surrounding lexical tokens. No linear-white-
+ space is permitted between them. The presence of one LWSP-
+ char between other tokens is still directed.
+
+ C.2.2. ATOM
+
+ Atoms may not contain SPACE.
+
+ C.2.3. SPECIAL TEXT
+
+ ctext and qtext have had backslash ("\") added to the list of
+ prohibited characters.
+
+ C.2.4. DOMAINS
+
+ The lexical tokens <domain-literal> and <dtext> have been
+ added.
+
+ C.3. MESSAGE SPECIFICATION
+
+ C.3.1. TRACE
+
+ The "Return-path:" and "Received:" fields have been specified.
+
+
+
+
+
+ August 13, 1982 - 41 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ C.3.2. FROM
+
+ The "From" field must contain machine-usable addresses (addr-
+ spec). Multiple addresses may be specified, but named-lists
+ (groups) may not.
+
+ C.3.3. RESENT
+
+ The meta-construct of prefacing field names with the string
+ "Resent-" has been added, to indicate that a message has been
+ forwarded by an intermediate recipient.
+
+ C.3.4. DESTINATION
+
+ A message must contain at least one destination address field.
+ "To" and "CC" are required to contain at least one address.
+
+ C.3.5. IN-REPLY-TO
+
+ The field-body is no longer a comma-separated list, although a
+ sequence is still permitted.
+
+ C.3.6. REFERENCE
+
+ The field-body is no longer a comma-separated list, although a
+ sequence is still permitted.
+
+ C.3.7. ENCRYPTED
+
+ A field has been specified that permits senders to indicate
+ that the body of a message has been encrypted.
+
+ C.3.8. EXTENSION-FIELD
+
+ Extension fields are prohibited from beginning with the char-
+ acters "X-".
+
+ C.4. DATE AND TIME SPECIFICATION
+
+ C.4.1. SIMPLIFICATION
+
+ Fewer optional forms are permitted and the list of three-
+ letter time zones has been shortened.
+
+ C.5. ADDRESS SPECIFICATION
+
+
+
+
+
+
+ August 13, 1982 - 42 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ C.5.1. ADDRESS
+
+ The use of quoted-string, and the ":"-atom-":" construct, have
+ been removed. An address now is either a single mailbox
+ reference or is a named list of addresses. The latter indi-
+ cates a group distribution.
+
+ C.5.2. GROUPS
+
+ Group lists are now required to to have a name. Group lists
+ may not be nested.
+
+ C.5.3. MAILBOX
+
+ A mailbox specification may indicate a person's name, as
+ before. Such a named list no longer may specify multiple
+ mailboxes and may not be nested.
+
+ C.5.4. ROUTE ADDRESSING
+
+ Addresses now are taken to be absolute, global specifications,
+ independent of transmission paths. The <route> construct has
+ been provided, to permit explicit specification of transmis-
+ sion path. RFC #733's use of multiple at-signs ("@") was
+ intended as a general syntax for indicating routing and/or
+ hierarchical addressing. The current standard separates these
+ specifications and only one at-sign is permitted.
+
+ C.5.5. AT-SIGN
+
+ The string " at " no longer is used as an address delimiter.
+ Only at-sign ("@") serves the function.
+
+ C.5.6. DOMAINS
+
+ Hierarchical, logical name-domains have been added.
+
+ C.6. RESERVED ADDRESS
+
+ The local-part "Postmaster" has been reserved, so that users can
+ be guaranteed at least one valid address at a site.
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 43 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ D. ALPHABETICAL LISTING OF SYNTAX RULES
+
+ address = mailbox ; one addressee
+ / group ; named list
+ addr-spec = local-part "@" domain ; global address
+ ALPHA = <any ASCII alphabetic character>
+ ; (101-132, 65.- 90.)
+ ; (141-172, 97.-122.)
+ atom = 1*<any CHAR except specials, SPACE and CTLs>
+ authentic = "From" ":" mailbox ; Single author
+ / ( "Sender" ":" mailbox ; Actual submittor
+ "From" ":" 1#mailbox) ; Multiple authors
+ ; or not sender
+ CHAR = <any ASCII character> ; ( 0-177, 0.-127.)
+ comment = "(" *(ctext / quoted-pair / comment) ")"
+ CR = <ASCII CR, carriage return> ; ( 15, 13.)
+ CRLF = CR LF
+ ctext = <any CHAR excluding "(", ; => may be folded
+ ")", "\" & CR, & including
+ linear-white-space>
+ CTL = <any ASCII control ; ( 0- 37, 0.- 31.)
+ character and DEL> ; ( 177, 127.)
+ date = 1*2DIGIT month 2DIGIT ; day month year
+ ; e.g. 20 Jun 82
+ dates = orig-date ; Original
+ [ resent-date ] ; Forwarded
+ date-time = [ day "," ] date time ; dd mm yy
+ ; hh:mm:ss zzz
+ day = "Mon" / "Tue" / "Wed" / "Thu"
+ / "Fri" / "Sat" / "Sun"
+ delimiters = specials / linear-white-space / comment
+ destination = "To" ":" 1#address ; Primary
+ / "Resent-To" ":" 1#address
+ / "cc" ":" 1#address ; Secondary
+ / "Resent-cc" ":" 1#address
+ / "bcc" ":" #address ; Blind carbon
+ / "Resent-bcc" ":" #address
+ DIGIT = <any ASCII decimal digit> ; ( 60- 71, 48.- 57.)
+ domain = sub-domain *("." sub-domain)
+ domain-literal = "[" *(dtext / quoted-pair) "]"
+ domain-ref = atom ; symbolic reference
+ dtext = <any CHAR excluding "[", ; => may be folded
+ "]", "\" & CR, & including
+ linear-white-space>
+ extension-field =
+ <Any field which is defined in a document
+ published as a formal extension to this
+ specification; none will have names beginning
+ with the string "X-">
+
+
+ August 13, 1982 - 44 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ field = field-name ":" [ field-body ] CRLF
+ fields = dates ; Creation time,
+ source ; author id & one
+ 1*destination ; address required
+ *optional-field ; others optional
+ field-body = field-body-contents
+ [CRLF LWSP-char field-body]
+ field-body-contents =
+ <the ASCII characters making up the field-body, as
+ defined in the following sections, and consisting
+ of combinations of atom, quoted-string, and
+ specials tokens, or else consisting of texts>
+ field-name = 1*<any CHAR, excluding CTLs, SPACE, and ":">
+ group = phrase ":" [#mailbox] ";"
+ hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
+ ; 00:00:00 - 23:59:59
+ HTAB = <ASCII HT, horizontal-tab> ; ( 11, 9.)
+ LF = <ASCII LF, linefeed> ; ( 12, 10.)
+ linear-white-space = 1*([CRLF] LWSP-char) ; semantics = SPACE
+ ; CRLF => folding
+ local-part = word *("." word) ; uninterpreted
+ ; case-preserved
+ LWSP-char = SPACE / HTAB ; semantics = SPACE
+ mailbox = addr-spec ; simple address
+ / phrase route-addr ; name & addr-spec
+ message = fields *( CRLF *text ) ; Everything after
+ ; first null line
+ ; is message body
+ month = "Jan" / "Feb" / "Mar" / "Apr"
+ / "May" / "Jun" / "Jul" / "Aug"
+ / "Sep" / "Oct" / "Nov" / "Dec"
+ msg-id = "<" addr-spec ">" ; Unique message id
+ optional-field =
+ / "Message-ID" ":" msg-id
+ / "Resent-Message-ID" ":" msg-id
+ / "In-Reply-To" ":" *(phrase / msg-id)
+ / "References" ":" *(phrase / msg-id)
+ / "Keywords" ":" #phrase
+ / "Subject" ":" *text
+ / "Comments" ":" *text
+ / "Encrypted" ":" 1#2word
+ / extension-field ; To be defined
+ / user-defined-field ; May be pre-empted
+ orig-date = "Date" ":" date-time
+ originator = authentic ; authenticated addr
+ [ "Reply-To" ":" 1#address] )
+ phrase = 1*word ; Sequence of words
+
+
+
+
+ August 13, 1982 - 45 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ qtext = <any CHAR excepting <">, ; => may be folded
+ "\" & CR, and including
+ linear-white-space>
+ quoted-pair = "\" CHAR ; may quote any char
+ quoted-string = <"> *(qtext/quoted-pair) <">; Regular qtext or
+ ; quoted chars.
+ received = "Received" ":" ; one per relay
+ ["from" domain] ; sending host
+ ["by" domain] ; receiving host
+ ["via" atom] ; physical path
+ *("with" atom) ; link/mail protocol
+ ["id" msg-id] ; receiver msg id
+ ["for" addr-spec] ; initial form
+ ";" date-time ; time received
+
+ resent = resent-authentic
+ [ "Resent-Reply-To" ":" 1#address] )
+ resent-authentic =
+ = "Resent-From" ":" mailbox
+ / ( "Resent-Sender" ":" mailbox
+ "Resent-From" ":" 1#mailbox )
+ resent-date = "Resent-Date" ":" date-time
+ return = "Return-path" ":" route-addr ; return address
+ route = 1#("@" domain) ":" ; path-relative
+ route-addr = "<" [route] addr-spec ">"
+ source = [ trace ] ; net traversals
+ originator ; original mail
+ [ resent ] ; forwarded
+ SPACE = <ASCII SP, space> ; ( 40, 32.)
+ specials = "(" / ")" / "<" / ">" / "@" ; Must be in quoted-
+ / "," / ";" / ":" / "\" / <"> ; string, to use
+ / "." / "[" / "]" ; within a word.
+ sub-domain = domain-ref / domain-literal
+ text = <any CHAR, including bare ; => atoms, specials,
+ CR & bare LF, but NOT ; comments and
+ including CRLF> ; quoted-strings are
+ ; NOT recognized.
+ time = hour zone ; ANSI and Military
+ trace = return ; path to sender
+ 1*received ; receipt tags
+ user-defined-field =
+ <Any field which has not been defined
+ in this specification or published as an
+ extension to this specification; names for
+ such fields must be unique and may be
+ pre-empted by published extensions>
+ word = atom / quoted-string
+
+
+
+
+ August 13, 1982 - 46 - RFC #822
+
+
+
+ Standard for ARPA Internet Text Messages
+
+
+ zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ <"> = <ASCII quote mark> ; ( 42, 34.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ August 13, 1982 - 47 - RFC #822
+
diff --git a/usr.sbin/sendmail/doc/usenix/Makefile b/usr.sbin/sendmail/doc/usenix/Makefile
new file mode 100644
index 0000000..ea0665c
--- /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 0000000..0fbb672
--- /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/doc/usenix/usenix.ps b/usr.sbin/sendmail/doc/usenix/usenix.ps
new file mode 100644
index 0000000..31f2f67
--- /dev/null
+++ b/usr.sbin/sendmail/doc/usenix/usenix.ps
@@ -0,0 +1,1004 @@
+%!PS-Adobe-3.0
+%%Creator: groff version 1.08
+%%DocumentNeededResources: font Times-Roman
+%%+ font Times-Italic
+%%+ font Times-Bold
+%%DocumentSuppliedResources: procset grops 1.08 0
+%%Pages: 9
+%%PageOrder: Ascend
+%%Orientation: Portrait
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset grops 1.08 0
+/setpacking where{
+pop
+currentpacking
+true setpacking
+}if
+/grops 120 dict dup begin
+/SC 32 def
+/A/show load def
+/B{0 SC 3 -1 roll widthshow}bind def
+/C{0 exch ashow}bind def
+/D{0 exch 0 SC 5 2 roll awidthshow}bind def
+/E{0 rmoveto show}bind def
+/F{0 rmoveto 0 SC 3 -1 roll widthshow}bind def
+/G{0 rmoveto 0 exch ashow}bind def
+/H{0 rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/I{0 exch rmoveto show}bind def
+/J{0 exch rmoveto 0 SC 3 -1 roll widthshow}bind def
+/K{0 exch rmoveto 0 exch ashow}bind def
+/L{0 exch rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/M{rmoveto show}bind def
+/N{rmoveto 0 SC 3 -1 roll widthshow}bind def
+/O{rmoveto 0 exch ashow}bind def
+/P{rmoveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/Q{moveto show}bind def
+/R{moveto 0 SC 3 -1 roll widthshow}bind def
+/S{moveto 0 exch ashow}bind def
+/T{moveto 0 exch 0 SC 5 2 roll awidthshow}bind def
+/SF{
+findfont exch
+[exch dup 0 exch 0 exch neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/MF{
+findfont
+[5 2 roll
+0 3 1 roll
+neg 0 0]makefont
+dup setfont
+[exch/setfont cvx]cvx bind def
+}bind def
+/level0 0 def
+/RES 0 def
+/PL 0 def
+/LS 0 def
+/PLG{
+gsave newpath clippath pathbbox grestore
+exch pop add exch pop
+}bind def
+/BP{
+/level0 save def
+1 setlinecap
+1 setlinejoin
+72 RES div dup scale
+LS{
+90 rotate
+}{
+0 PL translate
+}ifelse
+1 -1 scale
+}bind def
+/EP{
+level0 restore
+showpage
+}bind def
+/DA{
+newpath arcn stroke
+}bind def
+/SN{
+transform
+.25 sub exch .25 sub exch
+round .25 add exch round .25 add exch
+itransform
+}bind def
+/DL{
+SN
+moveto
+SN
+lineto stroke
+}bind def
+/DC{
+newpath 0 360 arc closepath
+}bind def
+/TM matrix def
+/DE{
+TM currentmatrix pop
+translate scale newpath 0 0 .5 0 360 arc closepath
+TM setmatrix
+}bind def
+/RC/rcurveto load def
+/RL/rlineto load def
+/ST/stroke load def
+/MT/moveto load def
+/CL/closepath load def
+/FL{
+currentgray exch setgray fill setgray
+}bind def
+/BL/fill load def
+/LW/setlinewidth load def
+/RE{
+findfont
+dup maxlength 1 index/FontName known not{1 add}if dict begin
+{
+1 index/FID ne{def}{pop pop}ifelse
+}forall
+/Encoding exch def
+dup/FontName exch def
+currentdict end definefont pop
+}bind def
+/DEFS 0 def
+/EBEGIN{
+moveto
+DEFS begin
+}bind def
+/EEND/end load def
+/CNT 0 def
+/level1 0 def
+/PBEGIN{
+/level1 save def
+translate
+div 3 1 roll div exch scale
+neg exch neg exch translate
+0 setgray
+0 setlinecap
+1 setlinewidth
+0 setlinejoin
+10 setmiterlimit
+[]0 setdash
+/setstrokeadjust where{
+pop
+false setstrokeadjust
+}if
+/setoverprint where{
+pop
+false setoverprint
+}if
+newpath
+/CNT countdictstack def
+userdict begin
+/showpage{}def
+}bind def
+/PEND{
+clear
+countdictstack CNT sub{end}repeat
+level1 restore
+}bind def
+end def
+/setpacking where{
+pop
+setpacking
+}if
+%%EndResource
+%%IncludeResource: font Times-Roman
+%%IncludeResource: font Times-Italic
+%%IncludeResource: font Times-Bold
+grops begin/DEFS 1 dict def DEFS begin/u{.001 mul}bind def end/RES 72 def/PL
+792 def/LS false def/ENC0[/asciicircum/asciitilde/Scaron/Zcaron/scaron/zcaron
+/Ydieresis/trademark/quotesingle/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
+/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/space
+/exclam/quotedbl/numbersign/dollar/percent/ampersand/quoteright/parenleft
+/parenright/asterisk/plus/comma/hyphen/period/slash/zero/one/two/three/four
+/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question/at/A/B/C
+/D/E/F/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash
+/bracketright/circumflex/underscore/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q
+/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/tilde/.notdef/quotesinglbase
+/guillemotleft/guillemotright/bullet/florin/fraction/perthousand/dagger
+/daggerdbl/endash/emdash/ff/fi/fl/ffi/ffl/dotlessi/dotlessj/grave/hungarumlaut
+/dotaccent/breve/caron/ring/ogonek/quotedblleft/quotedblright/oe/lslash
+/quotedblbase/OE/Lslash/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar
+/section/dieresis/copyright/ordfeminine/guilsinglleft/logicalnot/minus
+/registered/macron/degree/plusminus/twosuperior/threesuperior/acute/mu
+/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guilsinglright
+/onequarter/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumflex/Atilde
+/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute
+/Icircumflex/Idieresis/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis
+/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
+/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute
+/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis/eth/ntilde/ograve
+/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex
+/udieresis/yacute/thorn/ydieresis]def/Times-Bold@0 ENC0/Times-Bold RE
+/Times-Italic@0 ENC0/Times-Italic RE/Times-Roman@0 ENC0/Times-Roman RE
+%%EndProlog
+%%Page: 1 1
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 14/Times-Roman@0 SF(Mail Systems and Addressing)204.196 141 Q(in 4.2bsd)
+262.331 157.8 Q/F1 10/Times-Roman@0 SF(Eric Allman*)260.92 181.8 Q/F2 10
+/Times-Italic@0 SF(Britton-Lee)254.86 199.8 Q 2.5(,I)-.1 G(nc.)309.2 199.8 Q
+(1919 Addison Str)225.13 211.8 Q(eet, Suite 105.)-.37 E(Berk)232.645 223.8 Q
+(ele)-.1 E 1.1 -.55(y, C)-.3 H(alifornia 94704.).55 E F1(eric@Berk)244.175
+241.8 Q(ele)-.1 E -.65(y.)-.15 G(ARP).65 E(A)-.92 E(ucb)264.6 253.8 Q -.25(va)
+-.15 G(x!eric).25 E(ABSTRA)262.085 286.2 Q(CT)-.4 E .966
+(Routing mail through a heterogeneous internet presents man)112 302.4 R 3.466
+(yn)-.15 G 1.466 -.25(ew p)373.438 302.4 T 3.466(roblems. Among).25 F .297
+(the w)112 314.4 R .297(orst of these is that of address mapping.)-.1 F
+(Historically)5.297 E 2.797(,t)-.65 G .298(his has been handled on an)355.03
+314.4 R(ad hoc basis.)112 326.4 Q(Ho)5 E(we)-.25 E -.15(ve)-.25 G .8 -.4(r, t)
+.15 H(his approach has become unmanageable as internets gro).4 E -.65(w.)-.25 G
+.099(Sendmail acts a uni\214ed \231post of)112 342.6 R .098
+(\214ce\232 to which all mail can be submitted.)-.25 F .098(Address inter)5.098
+F(-)-.2 E .754(pretation is controlled by a production system, which can parse\
+ both old and ne)112 354.6 R 3.255(wf)-.25 G(or)452.54 354.6 Q(-)-.2 E .242
+(mat addresses.)112 366.6 R .242(The ne)5.242 F 2.742(wf)-.25 G .242
+(ormat is \231domain-based,)216.578 366.6 R 2.742<9a618d>-.7 G -.15(ex)334.326
+366.6 S .241(ible technique that can handle).15 F(man)112 378.6 Q 2.606(yc)-.15
+G .106(ommon situations.)141.116 378.6 R .106
+(Sendmail is not intended to perform user interf)5.106 F .107(ace functions.)
+-.1 F .399(Sendmail will replace deli)112 394.8 R -.15(ve)-.25 G .399
+(rmail in the Berk).15 F(ele)-.1 E 2.899(y4)-.15 G .399(.2 distrib)320.504
+394.8 R 2.899(ution. Se)-.2 F -.15(ve)-.25 G .399(ral major hosts).15 F .421
+(are no)112 406.8 R 2.921(wo)-.25 G 2.921(rw)152.022 406.8 S .421
+(ill soon be running sendmail.)165.493 406.8 R .421(This change will af)5.421 F
+.422(fect an)-.25 F 2.922(yu)-.15 G .422(sers that route)407.056 406.8 R 1.5
+(mail through a sendmail g)112 418.8 R(ate)-.05 E -.1(wa)-.25 G 5.3 -.65(y. T)
+.1 H 1.5(he changes that will be user visible are empha-).65 F(sized.)112 430.8
+Q .906(The mail system to appear in 4.2bsd will contain a number of changes.)97
+475.2 R .906(Most of these changes are)5.906 F .469
+(based on the replacement of)72 487.2 R F2(delivermail)2.969 E F1 .469
+(with a ne)2.969 F 2.969(wm)-.25 G .469(odule called)292.871 487.2 R F2 2.97
+(sendmail. Sendmail)2.97 F F1 .47(implements a gen-)2.97 F 1.834
+(eral internetw)72 499.2 R 1.834(ork mail routing f)-.1 F(acility)-.1 E 4.333
+(,f)-.65 G 1.833(eaturing aliasing and forw)239.739 499.2 R 1.833
+(arding, automatic routing to netw)-.1 F(ork)-.1 E -.05(ga)72 511.2 S(te).05 E
+-.1(wa)-.25 G .205(ys, and \215e).1 F .205(xible con\214guration.)-.15 F .205
+(Of k)5.205 F .505 -.15(ey i)-.1 H .205
+(nterest to the mail system user will be the changes in the net-).15 F -.1(wo)
+72 523.2 S(rk addressing structure.).1 E .624(In a simple netw)97 539.4 R .624
+(ork, each node has an address, and resources can be identi\214ed with a host-\
+resource)-.1 F .374(pair; in particular)72 551.4 R 2.874(,t)-.4 G .374
+(he mail system can refer to users using a host-username pair)149.932 551.4 R
+5.374(.H)-.55 G .375(ost names and numbers)409.276 551.4 R(ha)72 563.4 Q .3
+-.15(ve t)-.2 H 2.5(ob).15 G 2.5(ea)108.31 563.4 S
+(dministered by a central authority)119.69 563.4 Q 2.5(,b)-.65 G
+(ut usernames can be assigned locally to each host.)263.82 563.4 Q .397
+(In an internet, multiple netw)97 579.6 R .396(orks with dif)-.1 F .396
+(ferent characteristics and managements must communicate.)-.25 F .389
+(In particular)72 591.6 R 2.889(,t)-.4 G .389
+(he syntax and semantics of resource identi\214cation change.)129.308 591.6 R
+.39(Certain special cases can be han-)5.389 F 1.033(dled tri)72 603.6 R 1.033
+(vially by)-.25 F F2 1.033(ad hoc)3.533 F F1 1.032(techniques, such as pro)
+3.533 F 1.032(viding netw)-.15 F 1.032
+(ork names that appear local to hosts on other)-.1 F(netw)72 615.6 Q 1.621
+(orks, as with the Ethernet at Xerox P)-.1 F 4.121(ARC. Ho)-.92 F(we)-.25 E
+-.15(ve)-.25 G 2.421 -.4(r, t).15 H 1.622(he general case is e).4 F 1.622
+(xtremely comple)-.15 F 4.122(x. F)-.15 F(or)-.15 E -.15(ex)72 627.6 S .29
+(ample, some netw).15 F .29(orks require that the route the message tak)-.1 F
+.29(es be e)-.1 F .29(xplicitly speci\214ed by the sender)-.15 F 2.79(,s)-.4 G
+(im-)490.11 627.6 Q 1.618(plifying the database update problem since only adja\
+cent hosts must be entered into the system tables,)72 639.6 R .573(while other\
+s use logical addressing, where the sender speci\214es the location of the rec\
+ipient b)72 651.6 R .573(ut not ho)-.2 F 3.072(wt)-.25 G(o)499 651.6 Q 1.065
+(get there.)72 663.6 R 1.065(Some netw)6.065 F 1.066(orks use a left-associati)
+-.1 F 1.366 -.15(ve s)-.25 H 1.066(yntax and others use a right-associati).15 F
+1.366 -.15(ve s)-.25 H 1.066(yntax, causing).15 F .32 LW 76 673.2 72 673.2 DL
+80 673.2 76 673.2 DL 84 673.2 80 673.2 DL 88 673.2 84 673.2 DL 92 673.2 88
+673.2 DL 96 673.2 92 673.2 DL 100 673.2 96 673.2 DL 104 673.2 100 673.2 DL 108
+673.2 104 673.2 DL 112 673.2 108 673.2 DL 116 673.2 112 673.2 DL 120 673.2 116
+673.2 DL 124 673.2 120 673.2 DL 128 673.2 124 673.2 DL 132 673.2 128 673.2 DL
+136 673.2 132 673.2 DL 140 673.2 136 673.2 DL 144 673.2 140 673.2 DL 148 673.2
+144 673.2 DL 152 673.2 148 673.2 DL 156 673.2 152 673.2 DL 160 673.2 156 673.2
+DL 164 673.2 160 673.2 DL 168 673.2 164 673.2 DL 172 673.2 168 673.2 DL 176
+673.2 172 673.2 DL 180 673.2 176 673.2 DL 184 673.2 180 673.2 DL 188 673.2 184
+673.2 DL 192 673.2 188 673.2 DL 196 673.2 192 673.2 DL 200 673.2 196 673.2 DL
+204 673.2 200 673.2 DL 208 673.2 204 673.2 DL 212 673.2 208 673.2 DL 216 673.2
+212 673.2 DL/F3 8/Times-Roman@0 SF .556(*A considerable part of this w)93.6
+685.2 R .556(ork w)-.08 F .556(as done while under the emplo)-.08 F 2.557(yo)
+-.08 G 2.557(ft)323.107 685.2 S .557(he INGRES Project at the Uni)330.552 685.2
+R -.12(ve)-.2 G .557(rsity of California at).12 F(Berk)72 694.8 Q(ele)-.08 E
+-.52(y.)-.12 G/F4 10/Times-Bold@0 SF(Mail Systems and Addr)72 756 Q
+(essing in 4.2bsd)-.18 E(1)499 756 Q EP
+%%Page: 2 2
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(2)
+499 60 Q/F1 10/Times-Roman@0 SF(ambiguity in mix)72 96 Q(ed addresses.)-.15 E
+.679(Internet standards seek to eliminate these problems.)97 112.2 R(Initially)
+5.678 E 3.178(,t)-.65 G .678(hese proposed e)353.138 112.2 R .678
+(xpanding the address)-.15 F .331
+(pairs to address triples, consisting of {netw)72 124.2 R .331
+(ork, host, username} triples.)-.1 F(Netw)5.332 E .332(ork numbers must be uni)
+-.1 F -.15(ve)-.25 G -.2(r-).15 G 1.452
+(sally agreed upon, and hosts can be assigned locally on each netw)72 136.2 R
+3.952(ork. The)-.1 F(user)3.952 E(-le)-.2 E -.15(ve)-.25 G 3.952(lp).15 G 1.452
+(resentation w)440.718 136.2 R(as)-.1 E .249(changed to address domains, compr\
+ised of a local resource identi\214cation and a hierarchical domain speci\214-)
+72 148.2 R 1.54(cation with a common static root.)72 160.2 R 1.539
+(The domain technique separates the issue of ph)6.539 F 1.539(ysical v)-.05 F
+1.539(ersus logical)-.15 F 3.001(addressing. F)72 172.2 R .501(or e)-.15 F .502
+(xample, an address of the form \231eric@a.cc.berk)-.15 F(ele)-.1 E -.65(y.)
+-.15 G .502(arpa\232 describes the logical or).65 F -.05(ga)-.18 G(niza-).05 E
+.443(tion of the address space \(user \231eric\232 on host \231a\232 in the Co\
+mputer Center at Berk)72 184.2 R(ele)-.1 E .443(y\) b)-.15 F .443
+(ut not the ph)-.2 F(ysical)-.05 E(netw)72 196.2 Q .934(orks used \(for e)-.1 F
+.934(xample, this could go o)-.15 F -.15(ve)-.15 G 3.434(rd).15 G(if)274.722
+196.2 Q .934(ferent netw)-.25 F .935
+(orks depending on whether \231a\232 were on an)-.1 F
+(ethernet or a store-and-forw)72 208.2 Q(ard netw)-.1 E(ork\).)-.1 E/F2 10
+/Times-Italic@0 SF(Sendmail)97 224.4 Q F1 .493
+(is intended to help bridge the g)2.993 F .493(ap between the totally)-.05 F F2
+.493(ad hoc)2.993 F F1 -.1(wo)2.993 G .493(rld of netw).1 F .493(orks that kno)
+-.1 F(w)-.25 E .854(nothing of each other and the clean, tightly-coupled w)72
+236.4 R .854(orld of unique netw)-.1 F .855(ork numbers.)-.1 F .855
+(It can accept old)5.855 F .633(arbitrary address syntax)72 248.4 R .632(es, r\
+esolving ambiguities using heuristics speci\214ed by the system administrator)
+-.15 F 3.132(,a)-.4 G(s)500.11 248.4 Q .347(well as domain-based addressing.)72
+260.4 R .347(It helps guide the con)5.347 F -.15(ve)-.4 G .347
+(rsion of message formats between disparate net-).15 F -.1(wo)72 272.4 S 3.395
+(rks. In).1 F(short,)3.395 E F2(sendmail)3.395 E F1 .894
+(is designed to assist a graceful transition to consistent internetw)3.395 F
+.894(ork addressing)-.1 F(schemes.)72 284.4 Q .689
+(Section 1 de\214nes some of the terms frequently left fuzzy when w)97 312.6 R
+.69(orking in mail systems.)-.1 F .69(Section 2)5.69 F .595
+(discusses the design goals for)72 324.6 R F2(sendmail)3.095 E F1 5.595(.I)C
+3.095(ns)243.33 324.6 S .595(ection 3, the ne)255.315 324.6 R 3.095(wa)-.25 G
+.594(ddress formats and basic features of)332.705 324.6 R F2(send-)3.094 E
+(mail)72 336.6 Q F1 .893(are described.)3.393 F .893
+(Section 4 discusses some of the special problems of the UUCP netw)5.893 F
+3.394(ork. The)-.1 F(dif)3.394 E(fer)-.25 E(-)-.2 E(ences between)72 348.6 Q F2
+(sendmail)2.5 E F1(and)2.5 E F2(delivermail)2.5 E F1
+(are presented in section 5.)2.5 E F0(DISCLAIMER:)112 376.8 Q F1 3.333(An)3.333
+G .833(umber of e)199.216 376.8 R .832
+(xamples in this paper use names of actual people and)-.15 F(or)112 388.8 Q
+-.05(ga)-.18 G 4.572(nizations. This).05 F 2.072
+(is not intended to imply a commitment or e)4.572 F -.15(ve)-.25 G 4.573(na).15
+G 4.573(ni)409.987 388.8 S(ntellectual)422.34 388.8 Q 1.094
+(agreement on the part of these people or or)112 400.8 R -.05(ga)-.18 G 3.594
+(nizations. In).05 F(particular)3.594 E 3.594(,B)-.4 G 1.094(ell T)408.896
+400.8 R(elephone)-.7 E .656
+(Laboratories \(BTL\), Digital Equipment Corporation \(DEC\), La)112 412.8 R
+.657(wrence Berk)-.15 F(ele)-.1 E 3.157(yL)-.15 G(abo-)446.23 412.8 Q 2.136
+(ratories \(LBL\), Britton-Lee Incorporated \(BLI\), and the Uni)112 424.8 R
+-.15(ve)-.25 G 2.136(rsity of California at).15 F(Berk)112 436.8 Q(ele)-.1 E
+3.088(ya)-.15 G .588(re not committed to an)155.378 436.8 R 3.089(yo)-.15 G
+3.089(ft)261.219 436.8 S .589(hese proposals at this time.)270.418 436.8 R .589
+(Much of this paper)5.589 F
+(represents no more than the personal opinions of the author)112 448.8 Q(.)-.55
+E F0 2.5(1. DEFINITIONS)72 477 R F1 .266(There are four basic concepts that mu\
+st be clearly distinguished when dealing with mail systems:)112 493.2 R .514
+(the user \(or the user')87 505.2 R 3.014(sa)-.55 G .515(gent\), the user')
+182.6 505.2 R 3.015(si)-.55 G .515(denti\214cation, the user')253.025 505.2 R
+3.015(sa)-.55 G .515(ddress, and the route.)354.56 505.2 R .515(These are dis-)
+5.515 F(tinguished primarily by their position independence.)87 517.2 Q F0 2.5
+(1.1. User)87 541.2 R(and Identi\214cation)2.5 E F1 .264
+(The user is the being \(a person or program\) that is creating or recei)127
+557.4 R .263(ving a message.)-.25 F(An)5.263 E F2 -.1(age)2.763 G(nt).1 E F1
+.659(is an entity operating on behalf of the user \212 such as a secretary who\
+ handles my mail.)102 569.4 R .66(or a pro-)5.66 F(gram that automatically ret\
+urns a message such as \231I am at the UNICOM conference.)102 581.4 Q<9a>-.7 E
+.931(The identi\214cation is the tag that goes along with the particular user)
+127 597.6 R 5.931(.T)-.55 G .931(his tag is completely)418.707 597.6 R .216
+(independent of location.)102 609.6 R -.15(Fo)5.216 G 2.716(re).15 G .216
+(xample, my identi\214cation is the string \231Eric Allman,)225.324 609.6 R
+2.717<9a61>-.7 G .217(nd this identi-)448.006 609.6 R 1.228
+(\214cation does not change whether I am located at U.C. Berk)102 621.6 R(ele)
+-.1 E 2.527 -.65(y, a)-.15 H 3.727(tB).65 G 1.227
+(ritton-Lee, or at a scienti\214c)390.502 621.6 R(institute in Austria.)102
+633.6 Q 2.379
+(Since the identi\214cation is frequently ambiguous \(e.g., there are tw)127
+649.8 R 4.879<6f99>-.1 G 2.38(Robert Henry\232s at)426.48 649.8 R(Berk)102
+661.8 Q(ele)-.1 E .316(y\) it is common to add other disambiguating informatio\
+n that is not strictly part of the iden-)-.15 F
+(ti\214cation \(e.g., Robert \231Code Generator\232 Henry v)102 673.8 Q
+(ersus Robert \231System Administrator\232 Henry\).)-.15 E F0 -1(Ve)72 756 S
+(rsion 8.2)1 E(USENIX \255 J)249.805 756 Q(an 83)-.15 E(Last Mod 11/27/93)
+424.55 756 Q EP
+%%Page: 3 3
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(3)
+499 60 Q 2.5(1.2. Addr)87 96 R(ess)-.18 E/F1 10/Times-Roman@0 SF .785
+(The address speci\214es a location.)127 112.2 R .786(As I mo)5.786 F 1.086
+-.15(ve a)-.15 H .786(round, my address changes.).15 F -.15(Fo)5.786 G 3.286
+(re).15 G .786(xample, my)455.994 112.2 R 9.712
+(address might change from \231eric@Berk)102 124.2 R(ele)-.1 E -.65(y.)-.15 G
+(ARP).65 E 9.711(A\232 to \231eric@bli.UUCP\232 or \231all-)-.92 F
+(man@IIASA.Austria\232 depending on my current af)102 136.2 Q(\214liation.)-.25
+E(Ho)127 152.4 Q(we)-.25 E -.15(ve)-.25 G 2.819 -.4(r, a).15 H 4.519(na).4 G
+2.019(ddress is independent of the location of an)188.018 152.4 R 2.019
+(yone else.)-.15 F 2.02(That is, my address)7.02 F .385(remains the same to e)
+102 164.4 R -.15(ve)-.25 G .385(ryone who might be sending me mail.).15 F -.15
+(Fo)5.385 G 2.885(re).15 G .385(xample, a person at MIT and a)379.22 164.4 R
+(person at USC could both send to \231eric@Berk)102 176.4 Q(ele)-.1 E -.65(y.)
+-.15 G(ARP).65 E(A\232 and ha)-.92 E .3 -.15(ve i)-.2 H 2.5(ta).15 G(rri)388.44
+176.4 Q .3 -.15(ve t)-.25 H 2.5(ot).15 G(he same mailbox.)422.48 176.4 Q .627
+(Ideally a \231white pages\232 service w)127 192.6 R .627(ould be pro)-.1 F
+.627(vided to map user identi\214cations into addresses)-.15 F .444(\(for e)102
+204.6 R .444(xample, see [Solomon81]\).)-.15 F .444
+(Currently this is handled by passing around scraps of paper or by)5.444 F
+(calling people on the telephone to \214nd out their address.)102 216.6 Q F0
+2.5(1.3. Route)87 240.6 R F1 .288(While an address speci\214es)127 256.8 R/F2
+10/Times-Italic@0 SF(wher)2.788 E(e)-.37 E F1 .289
+(to \214nd a mailbox, a route speci\214es)2.789 F F2(how)2.789 E F1 .289
+(to \214nd the mailbox.)2.789 F(Speci\214cally)102 268.8 Q 2.607(,i)-.65 G
+2.607(ts)156.457 268.8 S .106(peci\214es a path from sender to recei)165.734
+268.8 R -.15(ve)-.25 G 3.706 -.55(r. A).15 H 2.606(ss).55 G .106
+(uch, the route is potentially dif)343.364 268.8 R .106(ferent for)-.25 F -2.15
+-.25(ev e)102 280.8 T(ry pair of people in the electronic uni).25 E -.15(ve)
+-.25 G(rse.).15 E .258(Normally the route is hidden from the user by the softw)
+127 297 R 2.758(are. Ho)-.1 F(we)-.25 E -.15(ve)-.25 G 1.058 -.4(r, s).15 H
+.258(ome netw).4 F .258(orks put the)-.1 F -.2(bu)102 309 S 1.972
+(rden of determining the route onto the sender).2 F 6.971(.A)-.55 G 1.971
+(lthough this simpli\214es the softw)322.544 309 R 1.971(are, it also)-.1 F
+(greatly impairs the usability for most users.)102 321 Q(The UUCP netw)5 E
+(ork is an e)-.1 E(xample of such a netw)-.15 E(ork.)-.1 E F0 2.5(2. DESIGN)72
+345 R(GO)2.5 E(ALS)-.4 E F1(Design goals for)112 363.2 Q F2(sendmail)2.5 E/F3 7
+/Times-Roman@0 SF(1)216.71 359.2 Q F1(include:)222.71 363.2 Q 12.5
+(\(1\) Compatibility)92 379.4 R 1.363(with the e)3.863 F 1.363
+(xisting mail programs, including Bell v)-.15 F 1.363(ersion 6 mail, Bell v)
+-.15 F 1.364(ersion 7)-.15 F 3.589(mail, Berk)118.66 391.4 R(ele)-.1 E(y)-.15 E
+F2(Mail)6.089 E F1 3.589
+([Shoens79], BerkNet mail [Schmidt79], and hopefully UUCP mail)6.089 F([No)
+118.66 403.4 Q 2.5(witz78]. ARP)-.25 F(ANET mail [Crock)-.92 E(er82] w)-.1 E
+(as also required.)-.1 E 12.5(\(2\) Reliability)92 419.6 R 4.002(,i)-.65 G
+4.002(nt)169.522 419.6 S 1.502(he sense of guaranteeing that e)181.304 419.6 R
+-.15(ve)-.25 G 1.502(ry message is correctly deli).15 F -.15(ve)-.25 G 1.503
+(red or at least).15 F .368
+(brought to the attention of a human for correct disposal; no message should e)
+118.66 431.6 R -.15(ve)-.25 G 2.868(rb).15 G 2.868(ec)452.252 431.6 S
+(ompletely)464 431.6 Q 2.54(lost. This)118.66 443.6 R .04(goal w)2.54 F .041
+(as considered essential because of the emphasis on mail in our en)-.1 F 2.541
+(vironment. It)-.4 F 1.755
+(has turned out to be one of the hardest goals to satisfy)118.66 455.6 R 4.254
+(,e)-.65 G 1.754(specially in the f)363.756 455.6 R 1.754(ace of the man)-.1 F
+(y)-.15 E .977(anomalous message formats produced by v)118.66 467.6 R .977
+(arious ARP)-.25 F .977(ANET sites.)-.92 F -.15(Fo)5.977 G 3.478(re).15 G .978
+(xample, certain sites)420.114 467.6 R .069
+(generate improperly formated addresses, occasionally causing error)118.66
+479.6 R .069(-message loops.)-.2 F .068(Some hosts)5.069 F .766(use blanks in \
+names, causing problems with mail programs that assume that an address is one)
+118.66 491.6 R -.1(wo)118.66 503.6 S 3.924(rd. The).1 F 1.423
+(semantics of some \214elds are interpreted slightly dif)3.923 F 1.423
+(ferently by dif)-.25 F 1.423(ferent sites.)-.25 F(In)6.423 E(summary)118.66
+515.6 Q 3.022(,t)-.65 G .523(he obscure features of the ARP)163.532 515.6 R
+.523(ANET mail protocol really)-.92 F F2(ar)3.023 E(e)-.37 E F1 .523
+(used and are dif)3.023 F(\214cult)-.25 E(to support, b)118.66 527.6 Q
+(ut must be supported.)-.2 E 12.5(\(3\) Existing)92 543.8 R(softw)2.939 E .439
+(are to do actual deli)-.1 F -.15(ve)-.25 G .439(ry should be used whene).15 F
+-.15(ve)-.25 G 2.938(rp).15 G 2.938(ossible. This)387.658 543.8 R .438
+(goal deri)2.938 F -.15(ve)-.25 G 2.938(sa).15 G(s)500.11 543.8 Q
+(much from political and practical considerations as technical.)118.66 555.8 Q
+12.5(\(4\) Easy)92 572 R -.15(ex)2.898 G .398(pansion to f).15 F .398
+(airly comple)-.1 F 2.898(xe)-.15 G -.4(nv)261.06 572 S .399
+(ironments, including multiple connections to a single net-).4 F -.1(wo)118.66
+584 S .63(rk type \(such as with multiple UUCP or Ethernets\).).1 F .63
+(This goal requires consideration of the)5.63 F
+(contents of an address as well as its syntax in order to determine which g)
+118.66 596 Q(ate)-.05 E -.1(wa)-.25 G 2.5(yt).1 G 2.5(ou)443.48 596 S(se.)
+455.98 596 Q 12.5(\(5\) Con\214guration)92 612.2 R 1.048
+(information should not be compiled into the code.)3.548 F 3.549(As)6.049 G
+1.049(ingle compiled program)405.802 612.2 R .084
+(should be able to run as is at an)118.66 624.2 R 2.584(ys)-.15 G .083
+(ite \(barring such basic changes as the CPU type or the operat-)256.196 624.2
+R .342(ing system\).)118.66 636.2 R 1.942 -.8(We h)5.342 H -2.25 -.2(av e).8 H
+.343(found this seemingly unimportant goal to be critical in real life.)3.042 F
+(Besides)5.343 E .734(the simple problems that occur when an)118.66 648.2 R
+3.234(yp)-.15 G .734(rogram gets recompiled in a dif)295.568 648.2 R .733
+(ferent en)-.25 F(vironment,)-.4 E(man)118.66 660.2 Q 2.5(ys)-.15 G(ites lik)
+147.12 660.2 Q 2.5(et)-.1 G 2.5<6f99>183.69 660.2 S(\214ddle\232 with an)195.63
+660.2 Q(ything that the)-.15 E 2.5(yw)-.15 G(ill be recompiling an)327.27 660.2
+Q(yw)-.15 E(ay)-.1 E(.)-.65 E .32 LW 76 678.8 72 678.8 DL 80 678.8 76 678.8 DL
+84 678.8 80 678.8 DL 88 678.8 84 678.8 DL 92 678.8 88 678.8 DL 96 678.8 92
+678.8 DL 100 678.8 96 678.8 DL 104 678.8 100 678.8 DL 108 678.8 104 678.8 DL
+112 678.8 108 678.8 DL 116 678.8 112 678.8 DL 120 678.8 116 678.8 DL 124 678.8
+120 678.8 DL 128 678.8 124 678.8 DL 132 678.8 128 678.8 DL 136 678.8 132 678.8
+DL 140 678.8 136 678.8 DL 144 678.8 140 678.8 DL 148 678.8 144 678.8 DL 152
+678.8 148 678.8 DL 156 678.8 152 678.8 DL 160 678.8 156 678.8 DL 164 678.8 160
+678.8 DL 168 678.8 164 678.8 DL 172 678.8 168 678.8 DL 176 678.8 172 678.8 DL
+180 678.8 176 678.8 DL 184 678.8 180 678.8 DL 188 678.8 184 678.8 DL 192 678.8
+188 678.8 DL 196 678.8 192 678.8 DL 200 678.8 196 678.8 DL 204 678.8 200 678.8
+DL 208 678.8 204 678.8 DL 212 678.8 208 678.8 DL 216 678.8 212 678.8 DL/F4 5
+/Times-Roman@0 SF(1)93.6 689.2 Q/F5 8/Times-Roman@0 SF(This section mak)3.2 I
+(es no distinction between)-.08 E/F6 8/Times-Italic@0 SF(delivermail)2 E F5
+(and)2 E F6(sendmail.)2 E F0 -1(Ve)72 756 S(rsion 8.2)1 E(USENIX \255 J)249.805
+756 Q(an 83)-.15 E(Last Mod 11/27/93)424.55 756 Q EP
+%%Page: 4 4
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(4)
+499 60 Q/F1 10/Times-Roman@0 SF(\(6\))92 96 Q/F2 10/Times-Italic@0 SF(Sendmail)
+118.66 96 Q F1 .184(must be able to let v)2.684 F .184
+(arious groups maintain their o)-.25 F .184(wn mailing lists, and let indi)-.25
+F(viduals)-.25 E(specify their o)118.66 108 Q(wn forw)-.25 E
+(arding, without modifying the system alias \214le.)-.1 E 12.5(\(7\) Each)92
+124.2 R .313(user should be able to specify which mailer to e)2.814 F -.15(xe)
+-.15 G .313(cute to process mail being deli).15 F -.15(ve)-.25 G .313(red for)
+.15 F 3.098(him. This)118.66 136.2 R .598(feature allo)3.098 F .598
+(ws users who are using specialized mailers that use a dif)-.25 F .598
+(ferent format to)-.25 F -.2(bu)118.66 148.2 S .25(ild their en).2 F .25
+(vironment without changing the system, and f)-.4 F .25
+(acilitates specialized functions \(such)-.1 F(as returning an \231I am on v)
+118.66 160.2 Q(acation\232 message\).)-.25 E 12.5(\(8\) Netw)92 176.4 R 1.552
+(ork traf)-.1 F 1.552(\214c should be minimized by batching addresses to a sin\
+gle host where possible,)-.25 F(without assistance from the user)118.66 188.4 Q
+(.)-.55 E .375(These goals moti)112 204.6 R -.25(va)-.25 G .375
+(ted the architecture illustrated in \214gure 1.).25 F .374
+(The user interacts with a mail gen-)5.375 F .49(erating and sending program.)
+87 216.6 R .491(When the mail is created, the generator calls)5.49 F F2
+(sendmail)2.991 E F1 2.991(,w)C .491(hich routes the)444.138 216.6 R .841
+(message to the correct mailer\(s\).)87 228.6 R .841
+(Since some of the senders may be netw)5.841 F .84(ork serv)-.1 F .84
+(ers and some of the)-.15 F(mailers may be netw)87 240.6 Q(ork clients,)-.1 E
+F2(sendmail)2.5 E F1(may be used as an internet mail g)2.5 E(ate)-.05 E -.1(wa)
+-.25 G -.65(y.).1 G F0 2.5(3. USA)72 264.6 R(GE)-.55 E 2.5(3.1. Addr)87 288.6 R
+(ess F)-.18 E(ormats)-.25 E F1(Ar)127 304.8 Q .886
+(guments may be \215ags or addresses.)-.18 F .886(Flags set v)5.886 F .886
+(arious processing options.)-.25 F -.15(Fo)5.886 G(llo).15 E .886(wing \215ag)
+-.25 F(ar)102 316.8 Q .611(guments, address ar)-.18 F .611(guments may be gi)
+-.18 F -.15(ve)-.25 G 3.111(n. Addresses).15 F(follo)3.111 E 3.111(wt)-.25 G
+.611(he syntax in RFC822 [Crock)365.558 316.8 R(er82])-.1 E(for ARP)102 328.8 Q
+(ANET address formats.)-.92 E(In brief, the format is:)5 E 12.5(\(1\) An)107
+345 R(ything in parentheses is thro)-.15 E(wn a)-.25 E -.1(wa)-.15 G 2.5(y\().1
+G(as a comment\).)299.65 345 Q 12.5(\(2\) An)107 361.2 R .051
+(ything in angle brack)-.15 F .051(ets \(\231<)-.1 F .051
+(>\232\) is preferred o)1.666 F -.15(ve)-.15 G 2.551(ra).15 G -.15(ny)348.064
+361.2 S .051(thing else.).15 F .051(This rule implements the)5.051 F(ARP)133.66
+373.2 Q(ANET standard that addresses of the form)-.92 E .4 LW 77 408 72 408 DL
+79 408 74 408 DL 84 408 79 408 DL 89 408 84 408 DL 94 408 89 408 DL 99 408 94
+408 DL 104 408 99 408 DL 109 408 104 408 DL 114 408 109 408 DL 119 408 114 408
+DL 124 408 119 408 DL 129 408 124 408 DL 134 408 129 408 DL 139 408 134 408 DL
+144 408 139 408 DL 149 408 144 408 DL 154 408 149 408 DL 159 408 154 408 DL 164
+408 159 408 DL 169 408 164 408 DL 174 408 169 408 DL 179 408 174 408 DL 184 408
+179 408 DL 189 408 184 408 DL 194 408 189 408 DL 199 408 194 408 DL 204 408 199
+408 DL 209 408 204 408 DL 214 408 209 408 DL 219 408 214 408 DL 224 408 219 408
+DL 229 408 224 408 DL 234 408 229 408 DL 239 408 234 408 DL 244 408 239 408 DL
+249 408 244 408 DL 254 408 249 408 DL 259 408 254 408 DL 264 408 259 408 DL 269
+408 264 408 DL 274 408 269 408 DL 279 408 274 408 DL 284 408 279 408 DL 289 408
+284 408 DL 294 408 289 408 DL 299 408 294 408 DL 304 408 299 408 DL 309 408 304
+408 DL 314 408 309 408 DL 319 408 314 408 DL 324 408 319 408 DL 329 408 324 408
+DL 334 408 329 408 DL 339 408 334 408 DL 344 408 339 408 DL 349 408 344 408 DL
+354 408 349 408 DL 359 408 354 408 DL 364 408 359 408 DL 369 408 364 408 DL 374
+408 369 408 DL 379 408 374 408 DL 384 408 379 408 DL 389 408 384 408 DL 394 408
+389 408 DL 399 408 394 408 DL 404 408 399 408 DL 409 408 404 408 DL 414 408 409
+408 DL 419 408 414 408 DL 424 408 419 408 DL 429 408 424 408 DL 434 408 429 408
+DL 439 408 434 408 DL 444 408 439 408 DL 449 408 444 408 DL 454 408 449 408 DL
+459 408 454 408 DL 464 408 459 408 DL 469 408 464 408 DL 474 408 469 408 DL 479
+408 474 408 DL 484 408 479 408 DL 489 408 484 408 DL 494 408 489 408 DL 499 408
+494 408 DL 504 408 499 408 DL(Figure 1 \212 Sendmail System Structure.)208 660
+Q 77 672 72 672 DL 79 672 74 672 DL 84 672 79 672 DL 89 672 84 672 DL 94 672 89
+672 DL 99 672 94 672 DL 104 672 99 672 DL 109 672 104 672 DL 114 672 109 672 DL
+119 672 114 672 DL 124 672 119 672 DL 129 672 124 672 DL 134 672 129 672 DL 139
+672 134 672 DL 144 672 139 672 DL 149 672 144 672 DL 154 672 149 672 DL 159 672
+154 672 DL 164 672 159 672 DL 169 672 164 672 DL 174 672 169 672 DL 179 672 174
+672 DL 184 672 179 672 DL 189 672 184 672 DL 194 672 189 672 DL 199 672 194 672
+DL 204 672 199 672 DL 209 672 204 672 DL 214 672 209 672 DL 219 672 214 672 DL
+224 672 219 672 DL 229 672 224 672 DL 234 672 229 672 DL 239 672 234 672 DL 244
+672 239 672 DL 249 672 244 672 DL 254 672 249 672 DL 259 672 254 672 DL 264 672
+259 672 DL 269 672 264 672 DL 274 672 269 672 DL 279 672 274 672 DL 284 672 279
+672 DL 289 672 284 672 DL 294 672 289 672 DL 299 672 294 672 DL 304 672 299 672
+DL 309 672 304 672 DL 314 672 309 672 DL 319 672 314 672 DL 324 672 319 672 DL
+329 672 324 672 DL 334 672 329 672 DL 339 672 334 672 DL 344 672 339 672 DL 349
+672 344 672 DL 354 672 349 672 DL 359 672 354 672 DL 364 672 359 672 DL 369 672
+364 672 DL 374 672 369 672 DL 379 672 374 672 DL 384 672 379 672 DL 389 672 384
+672 DL 394 672 389 672 DL 399 672 394 672 DL 404 672 399 672 DL 409 672 404 672
+DL 414 672 409 672 DL 419 672 414 672 DL 424 672 419 672 DL 429 672 424 672 DL
+434 672 429 672 DL 439 672 434 672 DL 444 672 439 672 DL 449 672 444 672 DL 454
+672 449 672 DL 459 672 454 672 DL 464 672 459 672 DL 469 672 464 672 DL 474 672
+469 672 DL 479 672 474 672 DL 484 672 479 672 DL 489 672 484 672 DL 494 672 489
+672 DL 499 672 494 672 DL 504 672 499 672 DL F0 -1(Ve)72 756 S(rsion 8.2)1 E
+(USENIX \255 J)249.805 756 Q(an 83)-.15 E(Last Mod 11/27/93)424.55 756 Q EP
+%%Page: 5 5
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(5)
+499 60 Q/F1 10/Times-Roman@0 SF(user name <machine-address>)173.66 96 Q(will s\
+end to the electronic \231machine-address\232 rather than the human \231user n\
+ame.)133.66 112.2 Q<9a>-.7 E 12.5(\(3\) Double)107 128.4 R 2.246(quotes \()
+4.746 F -2.754 2.5("\) q)2.5 H 2.246
+(uote phrases; backslashes quote characters.)224.188 128.4 R 2.246
+(Backslashes are more)7.246 F(po)133.66 140.4 Q .654(werful in that the)-.25 F
+3.154(yw)-.15 G .655(ill cause otherwise equi)229.196 140.4 R -.25(va)-.25 G
+.655(lent phrases to compare dif).25 F .655(ferently \212 for)-.25 F -.15(ex)
+133.66 152.4 S(ample,).15 E/F2 10/Times-Italic@0 SF(user)3.873 E F1(and)3.873 E
+F2("user")3.872 E F1 1.372(are equi)3.872 F -.25(va)-.25 G 1.372(lent, b).25 F
+(ut)-.2 E F2(\\user)3.872 E F1 1.372(is dif)3.872 F 1.372
+(ferent from either of them.)-.25 F(This)6.372 E(might be used to a)133.66
+164.4 Q -.2(vo)-.2 G(id normal aliasing or duplicate suppression algorithms.).2
+E -.15(Pa)127 180.6 S 1.12(rentheses, angle brack).15 F 1.12
+(ets, and double quotes must be properly balanced and nested.)-.1 F(The)6.12 E
+(re)102 194.6 Q(writing rules control remaining parsing)-.25 E/F3 7
+/Times-Roman@0 SF(2)266.17 190.6 Q F1(.)269.67 194.6 Q .644(Although old style\
+ addresses are still accepted in most cases, the preferred address format is)
+127 210.8 R .299(based on ARP)102 222.8 R(ANET)-.92 E .299
+(-style domain-based addresses [Su82a].)-.92 F .299
+(These addresses are based on a hierar)5.299 F(-)-.2 E .13
+(chical, logical decomposition of the address space.)102 234.8 R .13
+(The addresses are hierarchical in a sense similar)5.13 F 1.133(to the U.S. po\
+stal addresses: the messages may \214rst be routed to the correct state, with \
+no initial)102 246.8 R .72
+(consideration of the city or other addressing details.)102 258.8 R .72
+(The addresses are logical in that each step in)5.72 F(the hierarch)102 270.8 Q
+2.5(yc)-.05 G
+(orresponds to a set of \231naming authorities\232 rather than a ph)161.37
+270.8 Q(ysical netw)-.05 E(ork.)-.1 E -.15(Fo)127 287 S 2.5(re).15 G
+(xample, the address:)147.53 287 Q(eric@HostA.BigSite.ARP)142 303.2 Q(A)-.92 E
+-.1(wo)102 319.4 S .851
+(uld \214rst look up the domain BigSite in the namespace administrated by ARP)
+.1 F 3.351(A. A)-.92 F .851(query could)3.351 F 1.476
+(then be sent to BigSite for interpretation of HostA.)102 331.4 R(Ev)6.475 E
+1.475(entually the mail w)-.15 F 1.475(ould arri)-.1 F 1.775 -.15(ve a)-.25 H
+3.975(tH).15 G(ostA,)482.61 331.4 Q(which w)102 343.4 Q
+(ould then do \214nal deli)-.1 E -.15(ve)-.25 G(ry to user \231eric.).15 E<9a>
+-.7 E F0 2.5(3.2. Mail)87 367.4 R(to Files and Pr)2.5 E(ograms)-.18 E F1 .609
+(Files and programs are le)127 383.6 R .609(gitimate message recipients.)-.15 F
+.609(Files pro)5.609 F .609(vide archi)-.15 F -.25(va)-.25 G 3.109(ls).25 G .61
+(torage of mes-)445.02 383.6 R .124
+(sages, useful for project administration and history)102 395.6 R 5.124(.P)-.65
+G .124(rograms are useful as recipients in a v)318.308 395.6 R .124(ariety of)
+-.25 F .69(situations, for e)102 407.6 R .691(xample, to maintain a public rep\
+ository of systems messages \(such as the Berk)-.15 F(ele)-.1 E(y)-.15 E F2
+(msgs)102 419.6 Q F1(program\).)2.5 E(An)127 435.8 Q 3.188(ya)-.15 G .688(ddre\
+ss passing through the initial parsing algorithm as a local address \(i.e, not\
+ appear)151.698 435.8 R(-)-.2 E .276(ing to be a v)102 447.8 R .276
+(alid address for another mailer\) is scanned for tw)-.25 F 2.776(os)-.1 G .277
+(pecial cases.)362.128 447.8 R .277(If pre\214x)5.277 F .277(ed by a v)-.15 F
+(erti-)-.15 E .18(cal bar \(\231)102 459.8 R .833<7c9a>.833 G 2.68(\)t)-.833 G
+.179(he rest of the address is processed as a shell command.)156.456 459.8 R
+.179(If the user name be)5.179 F .179(gins with a)-.15 F(slash mark \(\231/)102
+471.8 Q(\232\) the name is used as a \214le name, instead of a login name.).833
+E F0 2.5(3.3. Aliasing,)87 495.8 R -.25(Fo)2.5 G(rwarding, Inclusion).25 E F2
+(Sendmail)127 512 Q F1 1.074(reroutes mail three w)3.574 F 3.574(ays. Aliasing)
+-.1 F 1.075(applies system wide.)3.575 F -.15(Fo)6.075 G(rw).15 E 1.075
+(arding allo)-.1 F 1.075(ws each)-.25 F .233
+(user to reroute incoming mail destined for that account.)102 524 R .233
+(Inclusion directs)5.233 F F2(sendmail)2.733 E F1 .233(to read a \214le for)
+2.733 F 2.5(al)102 536 S
+(ist of addresses, and is normally used in conjunction with aliasing.)111.72
+536 Q F0 2.5(3.3.1. Aliasing)102 560 R F1 .065
+(Aliasing maps local addresses to address lists using a system-wide \214le.)142
+576.2 R .065(This \214le is hashed)5.065 F 1.546(to speed access.)117 588.2 R
+1.545(Only addresses that parse as local are allo)6.546 F 1.545
+(wed as aliases; this guarantees a)-.25 F(unique k)117 600.2 Q .3 -.15(ey \()
+-.1 H(since there are no nicknames for the local host\).).15 E F0 2.5(3.3.2. F)
+102 624.2 R(orwarding)-.25 E F1 .641
+(After aliasing, if an recipient address speci\214es a local user)142 640.4 R
+F2(sendmail)3.141 E F1 .641(searches for a \231.for)3.141 F(-)-.2 E -.1(wa)117
+652.4 S .413(rd\232 \214le in the recipient').1 F 2.913(sh)-.55 G .413
+(ome directory)235.335 652.4 R 5.413(.I)-.65 G 2.913(fi)302.161 652.4 S 2.913
+(te)311.184 652.4 S .413(xists, the message is)321.167 652.4 R F2(not)2.913 E
+F1 .412(sent to that user)2.913 F 2.912(,b)-.4 G(ut)496.22 652.4 Q .745
+(rather to the list of addresses in that \214le.)117 664.4 R .746
+(Often this list will contain only one address, and the)5.746 F
+(feature will be used for netw)117 676.4 Q(ork mail forw)-.1 E(arding.)-.1 E
+.32 LW 76 686 72 686 DL 80 686 76 686 DL 84 686 80 686 DL 88 686 84 686 DL 92
+686 88 686 DL 96 686 92 686 DL 100 686 96 686 DL 104 686 100 686 DL 108 686 104
+686 DL 112 686 108 686 DL 116 686 112 686 DL 120 686 116 686 DL 124 686 120 686
+DL 128 686 124 686 DL 132 686 128 686 DL 136 686 132 686 DL 140 686 136 686 DL
+144 686 140 686 DL 148 686 144 686 DL 152 686 148 686 DL 156 686 152 686 DL 160
+686 156 686 DL 164 686 160 686 DL 168 686 164 686 DL 172 686 168 686 DL 176 686
+172 686 DL 180 686 176 686 DL 184 686 180 686 DL 188 686 184 686 DL 192 686 188
+686 DL 196 686 192 686 DL 200 686 196 686 DL 204 686 200 686 DL 208 686 204 686
+DL 212 686 208 686 DL 216 686 212 686 DL/F4 5/Times-Roman@0 SF(2)93.6 696.4 Q
+/F5 8/Times-Roman@0 SF(Disclaimer: Some special processing is done after re)3.2
+I(writing local names; see belo)-.2 E -.52(w.)-.2 G F0 -1(Ve)72 756 S
+(rsion 8.2)1 E(USENIX \255 J)249.805 756 Q(an 83)-.15 E(Last Mod 11/27/93)
+424.55 756 Q EP
+%%Page: 6 6
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(6)
+499 60 Q/F1 10/Times-Roman@0 SF -.15(Fo)142 96 S(rw).15 E 1.152
+(arding also permits a user to specify a pri)-.1 F -.25(va)-.25 G 1.151
+(te incoming mailer).25 F 6.151(.F)-.55 G 1.151(or e)437.348 96 R 1.151
+(xample, for)-.15 F(-)-.2 E -.1(wa)117 108 S(rding to:).1 E -2.5 .833("| /)157
+124.2 T(usr/local/ne)-.833 E(wmail myname")-.25 E(will use a dif)117 140.4 Q
+(ferent incoming mailer)-.25 E(.)-.55 E F0 2.5(3.3.3. Inclusion)102 164.4 R F1
+(Inclusion is speci\214ed in RFC 733 [Crock)142 180.6 Q(er77] syntax:)-.1 E
+(:Include: pathname)157 196.8 Q .391
+(An address of this form reads the \214le speci\214ed by)117 213 R/F2 10
+/Times-Italic@0 SF(pathname)2.891 E F1 .391
+(and sends to all users listed in that)2.891 F(\214le.)117 225 Q .645
+(The intent is)142 241.2 R F2(not)3.145 E F1 .644
+(to support direct use of this feature, b)3.145 F .644
+(ut rather to use this as a subset of)-.2 F 2.5(aliasing. F)117 253.2 R(or e)
+-.15 E(xample, an alias of the form:)-.15 E
+(project: :include:/usr/project/userlist)157 269.4 Q 1.93(is a method of letti\
+ng a project maintain a mailing list without interaction with the system)117
+285.6 R(administration, e)117 297.6 Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)203.54
+297.6 S(he alias \214le is protected.)212.15 297.6 Q 2.025
+(It is not necessary to reb)142 313.8 R 2.025(uild the inde)-.2 F 4.524(xo)-.15
+G 4.524(nt)317.828 313.8 S 2.024(he alias database when a :include: list is)
+330.132 313.8 R(changed.)117 325.8 Q F0 2.5(3.4. Message)87 349.8 R(Collection)
+2.5 E F1 .857(Once all recipient addresses are parsed and v)127 366 R .857
+(eri\214ed, the message is collected.)-.15 F .857(The message)5.857 F .574
+(comes in tw)102 378 R 3.074(op)-.1 G .574
+(arts: a message header and a message body)164.452 378 R 3.074(,s)-.65 G .574
+(eparated by a blank line.)349.734 378 R .573(The body is)5.574 F
+(an uninterpreted sequence of te)102 390 Q(xt lines.)-.15 E
+(The header is formated as a series of lines of the form)127 406.2 Q
+(\214eld-name: \214eld-v)178 422.4 Q(alue)-.25 E(Field-v)102 438.6 Q 1.366
+(alue can be split across lines by starting the follo)-.25 F 1.366
+(wing lines with a space or a tab)-.25 F 6.366(.S)-.4 G(ome)486.78 438.6 Q .211
+(header \214elds ha)102 450.6 R .511 -.15(ve s)-.2 H .211
+(pecial internal meaning, and ha).15 F .511 -.15(ve a)-.2 H .211
+(ppropriate special processing.).15 F .21(Other headers)5.21 F
+(are simply passed through.)102 462.6 Q
+(Some header \214elds may be added automatically)5 E 2.5(,s)-.65 G
+(uch as time stamps.)413.53 462.6 Q F0 2.5(4. THE)72 486.6 R(UUCP PR)2.5 E
+(OBLEM)-.3 E F1 .43(Of particular interest is the UUCP netw)112 502.8 R 2.93
+(ork. The)-.1 F -.15(ex)2.93 G .43(plicit routing used in the UUCP en).15 F
+(vironment)-.4 E .909(causes a number of serious problems.)87 514.8 R .909
+(First, gi)5.909 F .908(ving out an address is impossible without kno)-.25 F
+.908(wing the)-.25 F .453(address of your potential correspondent.)87 526.8 R
+.454(This is typically handled by specifying the address relati)5.453 F .754
+-.15(ve t)-.25 H(o).15 E 1.208(some \231well-kno)87 538.8 R 1.208
+(wn\232 host \(e.g., ucb)-.25 F -.25(va)-.15 G 3.708(xo).25 G 3.708(rd)253.47
+538.8 S(ecv)265.508 538.8 Q 3.708(ax\). Second,)-.25 F 1.207(it is often dif)
+3.708 F 1.207(\214cult to compute the set of)-.25 F .157
+(addresses to reply to without some kno)87 550.8 R .157
+(wledge of the topology of the netw)-.25 F 2.657(ork. Although)-.1 F .157
+(it may be easy)2.657 F .352(for a human being to do this under man)87 562.8 R
+2.851(yc)-.15 G .351(ircumstances, a program does not ha)259.713 562.8 R .651
+-.15(ve e)-.2 H .351(qually sophisticated).15 F 1.153(heuristics b)87 574.8 R
+1.153(uilt in.)-.2 F 1.154(Third, certain addresses will become painfully and \
+unnecessarily long, as when a)6.153 F .406(message is routed through man)87
+586.8 R 2.906(yh)-.15 G .406(osts in the USENET)225.81 586.8 R 5.406(.A)-.74 G
+.406(nd \214nally)322.804 586.8 R 2.905(,c)-.65 G .405(ertain \231mix)370.465
+586.8 R .405(ed domain\232 addresses)-.15 F
+(are impossible to parse unambiguously \212 e.g.,)87 598.8 Q(decv)127 615 Q
+(ax!ucb)-.25 E -.25(va)-.15 G(x!lbl-h!user@LBL-CSAM).25 E .378(might ha)87
+631.2 R .678 -.15(ve m)-.2 H(an).15 E 2.878(yp)-.15 G .379
+(ossible resolutions, depending on whether the message w)164.574 631.2 R .379
+(as \214rst routed to decv)-.1 F .379(ax or)-.25 F(to LBL-CSAM.)87 643.2 Q 2.32
+-.8(To s)112 659.4 T(olv).8 E 3.22(et)-.15 G .72
+(his problem, the UUCP syntax w)152.49 659.4 R .719(ould ha)-.1 F 1.019 -.15
+(ve t)-.2 H 3.219(ob).15 G 3.219(ec)346.956 659.4 S .719
+(hanged to use addresses rather than)359.055 659.4 R 3.718(routes. F)87 671.4 R
+1.218(or e)-.15 F 1.218(xample, the address \231decv)-.15 F(ax!ucb)-.25 E -.25
+(va)-.15 G 1.218(x!eric\232 might be e).25 F 1.218(xpressed as \231eric@ucb)
+-.15 F -.25(va)-.15 G(x.UUCP\232).25 E .079(\(with the hop through decv)87
+683.4 R .079(ax implied\).)-.25 F .079(This address w)5.079 F .078
+(ould itself be a domain-based address; for e)-.1 F(xam-)-.15 E
+(ple, an address might be of the form:)87 695.4 Q(mark@d.cbosg.btl.UUCP)127
+711.6 Q F0 -1(Ve)72 756 S(rsion 8.2)1 E(USENIX \255 J)249.805 756 Q(an 83)-.15
+E(Last Mod 11/27/93)424.55 756 Q EP
+%%Page: 7 7
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(7)
+499 60 Q/F1 10/Times-Roman@0 SF .311(Hosts outside of Bell T)87 96 R .311
+(elephone Laboratories w)-.7 F .311(ould then only need to kno)-.1 F 2.811(wh)
+-.25 G .811 -.25(ow t)402.982 96 T 2.811(og).25 G .312(et to a designated)
+433.354 96 R(BTL relay)87 108 Q 2.5(,a)-.65 G(nd the BTL topology w)137.17 108
+Q(ould only be maintained inside Bell.)-.1 E .543(There are three major proble\
+ms associated with turning UUCP addresses into something reason-)112 124.2 R
+.465(able: de\214ning the namespace, creating and propag)87 136.2 R .465
+(ating the necessary softw)-.05 F .466(are, and b)-.1 F .466(uilding and main-)
+-.2 F(taining the database.)87 148.2 Q F0 2.5(4.1. De\214ning)87 172.2 R
+(the Namespace)2.5 E F1 1.015(Putting all UUCP hosts into a \215at namespace \
+\(e.g., \231...@host.UUCP\232\) is not practical for a)127 188.4 R .222
+(number of reasons.)102 200.4 R .222(First, with o)5.222 F -.15(ve)-.15 G 2.722
+(r1).15 G .222(600 sites already)253.292 200.4 R 2.722(,a)-.65 G .222
+(nd \(with the increasing a)329.958 200.4 R -.25(va)-.2 G .222
+(ilability of ine).25 F(x-)-.15 E(pensi)102 212.4 Q 1.973 -.15(ve m)-.25 H
+1.673(icrocomputers and autodialers\) se).15 F -.15(ve)-.25 G 1.672
+(ral thousand more coming within a fe).15 F 4.172(wy)-.25 G 1.672(ears, the)
+469.008 212.4 R .078
+(database update problem is simply intractable if the namespace is \215at.)102
+224.4 R .078(Second, there are almost cer)5.078 F(-)-.2 E 2.446
+(tainly name con\215icts today)102 236.4 R 7.446(.T)-.65 G 2.446
+(hird, as the number of sites gro)232.794 236.4 R 4.946(wt)-.25 G 2.446
+(he names become e)386.316 236.4 R -.15(ve)-.25 G 4.946(rl).15 G(ess)491.78
+236.4 Q(mnemonic.)102 248.4 Q .534(It seems ine)127 264.6 R .535
+(vitable that there be some sort of naming authority for the set of top le)-.25
+F -.15(ve)-.25 G 3.035(ln).15 G(ames)483.45 264.6 Q .157
+(in the UUCP domain, as unpleasant a possibility as that may seem.)102 276.6 R
+.157(It will simply not be possible to)5.157 F(ha)102 288.6 Q .536 -.15(ve o)
+-.2 H .236(ne host resolving all names.).15 F .236(It may ho)5.236 F(we)-.25 E
+-.15(ve)-.25 G 2.736(rb).15 G 2.736(ep)316.144 288.6 S .236
+(ossible to handle this in a f)328.32 288.6 R .237(ashion similar to)-.1 F
+1.582(that of assigning names of ne)102 300.6 R 1.582(wsgroups in USENET)-.25 F
+6.582(.H)-.74 G -.25(ow)334.758 300.6 S -2.15 -.25(ev e).25 H 2.382 -.4(r, i)
+.25 H 4.082(tw).4 G 1.582(ill be essential to encourage)386.582 300.6 R -2.15
+-.25(ev e)102 312.6 T .52(ryone to become subdomains of an e).25 F .52
+(xisting domain whene)-.15 F -.15(ve)-.25 G 3.02(rp).15 G .52(ossible \212 e)
+374.85 312.6 R -.15(ve)-.25 G 3.02(nt).15 G .52(hough this will)442.95 312.6 R
+.077(certainly bruise some e)102 324.6 R 2.577(gos. F)-.15 F .077(or e)-.15 F
+.077(xample, if a ne)-.15 F 2.577(wh)-.25 G .076
+(ost named \231blid\232 were to be added to the UUCP)310.843 324.6 R(netw)102
+336.6 Q .65(ork, it w)-.1 F .651(ould probably actually be addressed as \231d.\
+bli.UUCP\232 \(i.e., as host \231d\232 in the pseudo-)-.1 F
+(domain \231bli\232 rather than as host \231blid\232 in the UUCP domain\).)102
+348.6 Q F0 2.5(4.2. Cr)87 372.6 R(eating and Pr)-.18 E(opagating the Softwar)
+-.18 E(e)-.18 E F1 .078(The softw)127 388.8 R .078
+(are required to implement a consistent namespace is relati)-.1 F -.15(ve)-.25
+G .077(ly tri).15 F 2.577(vial. T)-.25 F .277 -.1(wo m)-.8 H(odules).1 E
+(are needed, one to handle incoming mail and one to handle outgoing mail.)102
+400.8 Q 1.136(The incoming module must be prepared to handle either old or ne)
+127 417 R 3.636(ws)-.25 G 1.136(tyle addresses.)416.448 417 R(Ne)6.136 E(w-)
+-.25 E .025(style addresses can be passed through unchanged.)102 429 R .024
+(Old style addresses must be turned into ne)5.025 F 2.524(ws)-.25 G(tyle)489
+429 Q(addresses where possible.)102 441 Q 2.247
+(The outgoing module is slightly trickier)127 457.2 R 7.247(.I)-.55 G 4.747(tm)
+309.932 457.2 S 2.247(ust do a database lookup on the recipient)325.239 457.2 R
+.823(addresses \(passed on the command line\) to determine what hosts to send \
+the message to.)102 469.2 R .823(If those)5.823 F .023(hosts do not accept ne)
+102 481.2 R .024(w-style addresses, it must transform all addresses in the hea\
+der of the message)-.25 F(into old style using the database lookup.)102 493.2 Q
+1.197(Both of these modules are straightforw)127 509.4 R 1.197(ard e)-.1 F
+1.197(xcept for the issue of modifying the header)-.15 F 6.197(.I)-.55 G(t)
+501.22 509.4 Q .944
+(seems prudent to choose one format for the message headers.)102 521.4 R -.15
+(Fo)5.944 G 3.444(ran).15 G .944(umber of reasons, Berk)391.448 521.4 R(ele)-.1
+E(y)-.15 E .824(has elected to use the ARP)102 533.4 R .824
+(ANET protocols for message formats.)-.92 F(Ho)5.823 E(we)-.25 E -.15(ve)-.25 G
+1.623 -.4(r, t).15 H .823(his protocol is some-).4 F(what dif)102 545.4 Q
+(\214cult to parse.)-.25 E(Propag)127 561.6 Q 1.903(ation is some)-.05 F 1.903
+(what more dif)-.25 F 4.403(\214cult. There)-.25 F 1.903(are a lar)4.403 F
+1.903(ge number of hosts connected to)-.18 F .812(UUCP that will w)102 573.6 R
+.811(ant to run completely standard systems \(for v)-.1 F .811
+(ery good reasons\).)-.15 F .811(The strate)5.811 F .811(gy is)-.15 F
+(not to con)102 585.6 Q -.15(ve)-.4 G(rt the entire netw).15 E
+(ork \212 only enough of it it alle)-.1 E(viate the problem.)-.25 E F0 2.5
+(4.3. Building)87 609.6 R(and Maintaining the Database)2.5 E F1 .127
+(This is by f)127 625.8 R .127(ar the most dif)-.1 F .128(\214cult problem.)
+-.25 F 2.628(Ap)5.128 G .128(rototype for this database already e)309.736 625.8
+R .128(xists, b)-.15 F .128(ut it is)-.2 F
+(maintained by hand and does not pretend to be complete.)102 637.8 Q .701(This\
+ problem will be reduced considerably if people choose to group their hosts in\
+to subdo-)127 654 R 3.219(mains. This)102 666 R -.1(wo)3.219 G .719
+(uld require a global update only when a ne).1 F 3.22(wt)-.25 G .72(op le)
+356.47 666 R -.15(ve)-.25 G 3.22(ld).15 G .72(omain joined the netw)396.95 666
+R(ork.)-.1 E 2.805(Am)102 678 S .305
+(essage to a host in a subdomain could simply be routed to a kno)119.805 678 R
+.304(wn domain g)-.25 F(ate)-.05 E -.1(wa)-.25 G 2.804(yf).1 G .304(or further)
+465.656 678 R 3.073(processing. F)102 690 R .573(or e)-.15 F .573(xample, the \
+address \231eric@a.bli.UUCP\232 might be routed to the \231bli\232 g)-.15 F
+(ate)-.05 E -.1(wa)-.25 G 3.074(yf).1 G(or)495.67 690 Q(redistrib)102 702 Q
+1.376(ution; ne)-.2 F 3.876(wh)-.25 G 1.375
+(osts could be added within BLI without notifying the rest of the w)187.632 702
+R 3.875(orld. Of)-.1 F(course, other hosts)102 714 Q/F2 10/Times-Italic@0 SF
+(could)2.5 E F1(be noti\214ed as an ef)2.5 E(\214cienc)-.25 E 2.5(ym)-.15 G
+(easure.)321.01 714 Q F0 -1(Ve)72 756 S(rsion 8.2)1 E(USENIX \255 J)249.805 756
+Q(an 83)-.15 E(Last Mod 11/27/93)424.55 756 Q EP
+%%Page: 8 8
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Bold@0 SF(Mail Systems and Addr)72 60 Q(essing in 4.2bsd)-.18 E(8)
+499 60 Q/F1 10/Times-Roman@0 SF .966(There may be more than one domain g)127 96
+R(ate)-.05 E -.1(wa)-.25 G 4.767 -.65(y. A).1 H .967
+(domain such as BTL, for instance, might)4.117 F(ha)102 108 Q .653 -.15(ve a d)
+-.2 H .353(ozen g).15 F(ate)-.05 E -.1(wa)-.25 G .353(ys to the outside w).1 F
+.352(orld; a non-BTL site could choose the closest g)-.1 F(ate)-.05 E -.1(wa)
+-.25 G 4.152 -.65(y. T).1 H(he).65 E .308(only restriction w)102 120 R .308
+(ould be that all g)-.1 F(ate)-.05 E -.1(wa)-.25 G .308
+(ys maintain a consistent vie).1 F 2.808(wo)-.25 G 2.808(ft)390.998 120 S .308
+(he domain the)399.916 120 R 2.808(yr)-.15 G(epresent.)468.18 120 Q F0 2.5
+(4.4. Logical)87 144 R(Structur)2.5 E(e)-.18 E F1(Logically)127 160.2 Q 3.803
+(,d)-.65 G 1.303(omains are or)175.983 160.2 R -.05(ga)-.18 G 1.303
+(nized into a tree.).05 F 1.303(There need not be a host actually associated)
+6.303 F .462(with each le)102 172.2 R -.15(ve)-.25 G 2.962(li).15 G 2.962(nt)
+168.806 172.2 S .462(he tree \212 for e)179.548 172.2 R .462
+(xample, there will be no host associated with the name \231UUCP)-.15 F -.7
+<2e9a>-1.11 G(Similarly)102 184.2 Q 3.115(,a)-.65 G 3.115(no)148.635 184.2 S
+-2.19 -.18(rg a)161.75 184.2 T .614
+(nization might group names together for administrati).18 F .914 -.15(ve r)-.25
+H .614(easons; for e).15 F .614(xample, the)-.15 F(name)102 196.2 Q
+(CAD.research.BigCorp.UUCP)142 212.4 Q(might not actually ha)102 228.6 Q .3
+-.15(ve a h)-.2 H(ost representing \231research.).15 E<9a>-.7 E(Ho)127 244.8 Q
+(we)-.25 E -.15(ve)-.25 G 1.531 -.4(r, i).15 H 3.231(tm).4 G .731
+(ay frequently be con)184.902 244.8 R -.15(ve)-.4 G .731(nient to ha).15 F
+1.031 -.15(ve a h)-.2 H .732(ost or hosts that \231represent\232 a domain.).15
+F -.15(Fo)102 256.8 S 3.466(re).15 G .966(xample, if a single host e)123.496
+256.8 R .966(xists that represents Berk)-.15 F(ele)-.1 E 2.266 -.65(y, t)-.15 H
+.966(hen mail from outside Berk).65 F(ele)-.1 E 3.466(yc)-.15 G(an)494.56 256.8
+Q(forw)102 268.8 Q .796
+(ard mail to that host for further resolution without kno)-.1 F .796(wing Berk)
+-.25 F(ele)-.1 E(y')-.15 E 3.296(s\()-.55 G .797(rather v)417.066 268.8 R .797
+(olatile\) topol-)-.2 F(ogy)102 280.8 Q 5(.T)-.65 G(his is not unlik)129.96
+280.8 Q 2.5(et)-.1 G(he operation of the telephone netw)198.76 280.8 Q(ork.)-.1
+E .053(This may also be useful inside certain lar)127 297 R .053(ge domains.)
+-.18 F -.15(Fo)5.053 G 2.553(re).15 G .053(xample, at Berk)365.352 297 R(ele)
+-.1 E 2.553(yi)-.15 G 2.553(tm)450.801 297 S .053(ay be pre-)463.914 297 R .722
+(sumed that most hosts kno)102 309 R 3.222(wa)-.25 G .722
+(bout other hosts inside the Berk)225.64 309 R(ele)-.1 E 3.223(yd)-.15 G 3.223
+(omain. But)380.825 309 R .723(if the)3.223 F 3.223(yp)-.15 G .723(rocess an)
+466.347 309 R .405(address that is unkno)102 321 R .405(wn, the)-.25 F 2.905
+(yc)-.15 G .405(an pass it \231upstairs\232 for further e)229.165 321 R 2.905
+(xamination. Thus)-.15 F .405(as ne)2.905 F 2.905(wh)-.25 G .405(osts are)
+473.325 321 R .488(added only one host \(the domain master\))102 333 R/F2 10
+/Times-Italic@0 SF(must)2.989 E F1 .489
+(be updated immediately; other hosts can be updated)2.989 F(as con)102 345 Q
+-.15(ve)-.4 G(nient.).15 E .583(Ideally this name resolution process w)127
+361.2 R .583(ould be performed by a name serv)-.1 F .582
+(er \(e.g., [Su82b]\) to)-.15 F -.2(avo)102 373.2 S .507(id unnecessary cop).2
+F .507(ying of the message.)-.1 F(Ho)5.507 E(we)-.25 E -.15(ve)-.25 G 1.307 -.4
+(r, i).15 H 3.007(nab).4 G .507(atch netw)346.623 373.2 R .508
+(ork such as UUCP this could)-.1 F(result in unnecessary delays.)102 385.2 Q F0
+2.5(5. COMP)72 409.2 R(ARISON WITH DELIVERMAIL)-.74 E F2(Sendmail)112 425.4 Q
+F1(is an outgro)2.5 E(wth of)-.25 E F2(delivermail)2.5 E F1 5(.T)C
+(he primary dif)286.18 425.4 Q(ferences are:)-.25 E 12.5(\(1\) Con\214guration)
+92 441.6 R .573(information is not compiled in.)3.073 F .572
+(This change simpli\214es man)5.572 F 3.072(yo)-.15 G 3.072(ft)433.684 441.6 S
+.572(he problems of)442.866 441.6 R(mo)118.66 453.6 Q(ving to other machines.)
+-.15 E(It also allo)5 E(ws easy deb)-.25 E(ugging of ne)-.2 E 2.5(wm)-.25 G
+(ailers.)388.06 453.6 Q 12.5(\(2\) Address)92 469.8 R .491
+(parsing is more \215e)2.991 F 2.991(xible. F)-.15 F .491(or e)-.15 F(xample,)
+-.15 E F2(delivermail)2.992 E F1 .492(only supported one g)2.992 F(ate)-.05 E
+-.1(wa)-.25 G 2.992(yt).1 G 2.992(oa)481.718 469.8 S -.15(ny)494.15 469.8 S
+(netw)118.66 481.8 Q(ork, whereas)-.1 E F2(sendmail)2.5 E F1(can be sensiti)2.5
+E .3 -.15(ve t)-.25 H 2.5(oh).15 G(ost names and reroute to dif)310.9 481.8 Q
+(ferent g)-.25 E(ate)-.05 E -.1(wa)-.25 G(ys.).1 E 12.5(\(3\) F)92 498 R(orw)
+-.15 E 2.878(arding and :include: features eliminate the requirement that the \
+system alias \214le be)-.1 F 1.073(writable by an)118.66 510 R 3.573(yu)-.15 G
+1.073
+(ser \(or that an update program be written, or that the system administration)
+191.439 510 R(mak)118.66 522 Q 2.5(ea)-.1 G(ll changes\).)147.16 522 Q(\(4\))92
+538.2 Q F2(Sendmail)118.66 538.2 Q F1 .443
+(supports message batching across netw)2.944 F .443
+(orks when a message is being sent to multiple)-.1 F(recipients.)118.66 550.2 Q
+12.5(\(5\) A)92 566.4 R 1.945(mail queue is pro)4.445 F 1.946(vided in)-.15 F
+F2(sendmail.)4.446 E F1 1.946(Mail that cannot be deli)6.946 F -.15(ve)-.25 G
+1.946(red immediately b).15 F 1.946(ut can)-.2 F .439(potentially be deli)
+118.66 578.4 R -.15(ve)-.25 G .438
+(red later is stored in this queue for a later retry).15 F 5.438(.T)-.65 G .438
+(he queue also pro)404.088 578.4 R .438(vides a)-.15 F -.2(bu)118.66 590.4 S
+-.25(ff).2 G .838(er ag).25 F .839(ainst system crashes; after the message has\
+ been collected it may be reliably redeli)-.05 F(v-)-.25 E(ered e)118.66 602.4
+Q -.15(ve)-.25 G 2.5(ni).15 G 2.5(ft)162.13 602.4 S
+(he system crashes during the initial deli)170.74 602.4 Q -.15(ve)-.25 G(ry).15
+E(.)-.65 E(\(6\))92 618.6 Q F2(Sendmail)118.66 618.6 Q F1 1.351(uses the netw)
+3.851 F 1.351(orking support pro)-.1 F 1.351(vided by 4.2BSD to pro)-.15 F 1.35
+(vide a direct interf)-.15 F 1.35(ace net-)-.1 F -.1(wo)118.66 630.6 S .283
+(rks such as the ARP).1 F .284
+(ANET and/or Ethernet using SMTP \(the Simple Mail T)-.92 F .284
+(ransfer Protocol\))-.35 F -.15(ove)118.66 642.6 S 2.5(raT).15 G
+(CP/IP connection.)151.68 642.6 Q F0 -1(Ve)72 756 S(rsion 8.2)1 E
+(USENIX \255 J)249.805 756 Q(an 83)-.15 E(Last Mod 11/27/93)424.55 756 Q EP
+%%Page: 9 9
+%%BeginPageSetup
+BP
+%%EndPageSetup
+/F0 10/Times-Roman@0 SF(REFERENCES)264.105 132 Q([Crock)87 148.2 Q 56.73
+(er77] Crock)-.1 F(er)-.1 E 3.535(,D)-.4 G 3.535(.H)239.965 148.2 S 1.035(., V)
+253.22 148.2 R 1.035(ittal, J. J., Pogran, K. T)-.6 F 1.035
+(., and Henderson, D. A. Jr)-.74 F(.,)-.55 E/F1 10/Times-Italic@0 SF(Stan-)
+3.535 E(dar)195 160.2 Q 2.627(df)-.37 G .127(or the F)218.927 160.2 R .127
+(ormat of ARP)-1.05 F 2.627(AN)-.9 G .128(etwork T)320.112 160.2 R -.2(ex)-.92
+G 2.628(tM).2 G(essa)377.018 160.2 Q -.1(ge)-.1 G(s.).1 E F0 .128
+(RFC 733, NIC 41952.)5.128 F(In [Feinler78].)195 172.2 Q(No)5 E -.15(ve)-.15 G
+(mber 1977.).15 E([Crock)87 188.4 Q 56.73(er82] Crock)-.1 F(er)-.1 E 4.272(,D)
+-.4 G 4.272(.H)240.702 188.4 S(.,)254.694 188.4 Q F1(Standar)4.272 E 4.272(df)
+-.37 G 1.772(or the F)307.318 188.4 R 1.772(ormat of Arpa Internet T)-1.05 F
+-.2(ex)-.92 G 4.271(tM).2 G(essa)471.15 188.4 Q -.1(ge)-.1 G(s.).1 E F0 .025
+(RFC 822.)195 200.4 R(Netw)5.025 E .025(ork Information Center)-.1 F 2.526(,S)
+-.4 G .026(RI International, Menlo P)363.506 200.4 R .026(ark, Cali-)-.15 F 2.5
+(fornia. August)195 212.4 R(1982.)2.5 E 60.51([Feinler78] Feinler)87 228.6 R
+2.938(,E)-.4 G .438(., and Postel, J.)234.478 228.6 R(\(eds.\),)5.438 E F1(ARP)
+2.938 E .438(ANET Pr)-.9 F .438(otocol Handbook.)-.45 F F0 .438(NIC 7104,)5.438
+F(Netw)195 240.6 Q 3.011(ork Information Center)-.1 F 5.511(,S)-.4 G 3.012
+(RI International, Menlo P)328.513 240.6 R 3.012(ark, California.)-.15 F(1978.)
+195 252.6 Q([No)87 268.8 Q 59.65(witz78] No)-.25 F .479
+(witz, D. A., and Lesk, M. E.,)-.25 F F1 2.978(AD)2.978 G .478
+(ial-Up Network of UNIX Systems.)344.67 268.8 R F0(Bell)5.478 E 3.528
+(Laboratories. In)195 280.8 R 1.029(UNIX Programmer')3.528 F 3.529(sM)-.55 G
+1.029(anual, Se)363.524 280.8 R -.15(ve)-.25 G 1.029(nth Edition, V).15 F 1.029
+(olume 2.)-1.29 F(August, 1978.)195 292.8 Q 55.5([Schmidt79] Schmidt,)87 309 R
+(E.,)2.631 E F1 .131(An Intr)2.631 F .131(oduction to the Berk)-.45 F(ele)-.1 E
+2.631(yN)-.3 G(etwork.)382.277 309 Q F0(Uni)5.131 E -.15(ve)-.25 G .131
+(rsity of Califor).15 F(-)-.2 E(nia, Berk)195 321 Q(ele)-.1 E 2.5(yC)-.15 G 2.5
+(alifornia. 1979.)257.24 321 R 59.95([Shoens79] Shoens,)87 337.2 R(K.,)3.227 E
+F1 .728(Mail Refer)3.227 F .728(ence Manual.)-.37 F F0(Uni)5.728 E -.15(ve)-.25
+G .728(rsity of California, Berk).15 F(ele)-.1 E 4.528 -.65(y. I)-.15 H(n).65 E
+3.478(UNIX Programmer')195 349.2 R 5.977(sM)-.55 G 3.477(anual, Se)297.495
+349.2 R -.15(ve)-.25 G 3.477(nth Edition, V).15 F 3.477(olume 2C.)-1.29 F
+(December)8.477 E(1979.)195 361.2 Q 52.72([Solomon81] Solomon,)87 377.4 R .251
+(M., Landweber)2.75 F 2.751(,L)-.4 G .251(., and Neuhengen, D.,)308.952 377.4 R
+F1 .251(The Design of the CSNET)2.751 F .397(Name Server)195 389.4 R(.)-1.11 E
+F0 2.896(CS-DN-2. Uni)5.397 F -.15(ve)-.25 G .396(rsity of W).15 F .396
+(isconsin, Madison.)-.4 F .396(October 1981.)5.396 F 73.84([Su82a] Su,)87 405.6
+R(Za)2.844 E .344(w-Sing, and Postel, Jon,)-.15 F F1 .344
+(The Domain Naming Con)2.844 F .344(vention for Internet)-.4 F 2.71
+(User Applications.)195 417.6 R F0 5.21(RFC819. Netw)7.71 F 2.71
+(ork Information Center)-.1 F 5.21(,S)-.4 G 2.71(RI Interna-)457.14 417.6 R
+(tional, Menlo P)195 429.6 Q(ark, California.)-.15 E(August 1982.)5 E 73.28
+([Su82b] Su,)87 445.8 R(Za)4.174 E(w-Sing,)-.15 E F1 4.174(AD)4.174 G(istrib)
+275.702 445.8 Q 1.675(uted System for Internet Name Service)-.2 F(.)-.15 E F0
+(RFC830.)6.675 E(Netw)195 457.8 Q 3.012(ork Information Center)-.1 F 5.512(,S)
+-.4 G 3.011(RI International, Menlo P)328.516 457.8 R 3.011(ark, California.)
+-.15 F(October 1982.)195 469.8 Q/F2 10/Times-Bold@0 SF(Mail Systems and Addr)72
+756 Q(essing in 4.2bsd)-.18 E(9)499 756 Q EP
+%%Trailer
+end
+%%EOF
diff --git a/usr.sbin/sendmail/mailstats/Makefile b/usr.sbin/sendmail/mailstats/Makefile
new file mode 100644
index 0000000..d6a04f0
--- /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 0000000..1e11b01
--- /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 0000000..c4ac74e
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+PROG= makemap
+MAN8= makemap.8
+CFLAGS+=-I${.CURDIR}/../src -DNDBM -DNEWDB
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/makemap/Makefile.dist b/usr.sbin/sendmail/makemap/Makefile.dist
new file mode 100644
index 0000000..3e7817a
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/Makefile.dist
@@ -0,0 +1,81 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.dist 8.2 (Berkeley) 11/27/93
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+# location of sendmail source directory
+SRCDIR= ../src
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# The really old (V7) DBM library is no longer supported.
+#
+DBMDEF= -DNDBM -DNEWDB
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I${SRCDIR} -I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -ldbm
+
+# location of makemap binary (usually /usr/sbin or /usr/etc)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= makemap.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= bin
+BINGRP= bin
+BINMODE=555
+
+ALL= makemap makemap.0
+
+all: ${ALL}
+
+makemap: ${BEFORE} ${OBJS}
+ ${CC} -o makemap ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+makemap.0: makemap.8
+ nroff -h -mandoc makemap.8 > makemap.0
+
+install: install-makemap install-docs
+
+install-makemap: makemap
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} makemap ${BINDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: makemap.0
+
+clean:
+ rm -f ${OBJS} makemap makemap.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: ${SRCDIR}/conf.h
diff --git a/usr.sbin/sendmail/makemap/makemap.8 b/usr.sbin/sendmail/makemap/makemap.8
new file mode 100644
index 0000000..2ee45c2
--- /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 0000000..f2d4aea
--- /dev/null
+++ b/usr.sbin/sendmail/makemap/makemap.c
@@ -0,0 +1,373 @@
+/*
+ * 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 (Berkeley) 11/22/93";
+#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;
+ int 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);
+ break;
+
+ case T_BTREE:
+ dbp.db = dbopen(mapname, mode, 0644, DB_BTREE, NULL);
+ 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 0000000..498e171
--- /dev/null
+++ b/usr.sbin/sendmail/praliases/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/7/93
+
+PROG= praliases
+CFLAGS+=-I${.CURDIR}/../src
+DPADD= ${LIBDBM}
+NOMAN= noman
+
+.include "../../Makefile.inc"
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sendmail/praliases/Makefile.dist b/usr.sbin/sendmail/praliases/Makefile.dist
new file mode 100644
index 0000000..a7b07f4
--- /dev/null
+++ b/usr.sbin/sendmail/praliases/Makefile.dist
@@ -0,0 +1,81 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.dist 8.1 (Berkeley) 11/27/93
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+# location of sendmail source directory
+SRCDIR= ../src
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# The really old (V7) DBM library is no longer supported.
+#
+DBMDEF= -DNDBM -DNEWDB
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I${SRCDIR} -I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -ldbm
+
+# location of praliases binary (usually /usr/sbin or /usr/etc)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= praliases.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= bin
+BINGRP= bin
+BINMODE=555
+
+ALL= praliases praliases.0
+
+all: ${ALL}
+
+praliases: ${BEFORE} ${OBJS}
+ ${CC} -o praliases ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+praliases.0: praliases.8
+ nroff -h -mandoc praliases.8 > praliases.0
+
+install: install-praliases install-docs
+
+install-praliases: praliases
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} praliases ${BINDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: praliases.0
+
+clean:
+ rm -f ${OBJS} praliases praliases.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: ${SRCDIR}/conf.h
diff --git a/usr.sbin/sendmail/praliases/praliases.c b/usr.sbin/sendmail/praliases/praliases.c
new file mode 100644
index 0000000..2c22279
--- /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 0000000..71f44ed
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile
@@ -0,0 +1,42 @@
+# @(#)Makefile 8.4 (Berkeley) 2/3/94
+
+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 -DNDBM
+
+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
+DPADD=
+LDADD=
+MAN1= mailq.1 newaliases.1
+MAN5= aliases.5
+MAN8= sendmail.8
+LINKS= /usr/sbin/sendmail /usr/bin/newaliases \
+ /usr/sbin/sendmail /usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+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.386BSD b/usr.sbin/sendmail/src/Makefile.386BSD
new file mode 100644
index 0000000..63d94aa
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.386BSD
@@ -0,0 +1,42 @@
+# @(#)Makefile.386BSD 8.1 (Berkeley) 2/26/94
+
+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
+
+CFLAGS+=-I${.CURDIR} ${DBMDEF} -DMIME
+
+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
+DPADD=
+LDADD= $(LIBUTIL)
+MAN1= newaliases.0 mailq.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
+BINGRP= kmem
+BINMODE=6555
+
+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.AIX b/usr.sbin/sendmail/src/Makefile.AIX
new file mode 100644
index 0000000..5d3041d
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.AIX
@@ -0,0 +1,113 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on AIX 3.1.5 and 3.2.3e.
+#
+# @(#)Makefile.AIX 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+# you can use -O3 on AIX 3.2.4 or greater ONLY!
+O= -g
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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 -DNIS
+#
+# If you did not install the NEWDB on your AIX platform, use:
+#DBMDEF=-DNDBM
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -D_AIX3
+
+# see also conf.h for additional compilation flags
+
+# include directories
+#INCDIRS=-I/usr/sww/include/db
+
+# library directories
+#LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldbm -ldb
+#
+# If you did not install the NEWDB on your AIX platform, use:
+#LIBS= -ldbm
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# 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
+
+# additional .o files needed
+OBJADD=
+
+INSTALL=/usr/ucb/install
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/sbin/newaliases ${DESTDIR}/usr/sbin/mailq
+BINOWN= root
+BINGRP= system
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.AUX b/usr.sbin/sendmail/src/Makefile.AUX
new file mode 100644
index 0000000..dc84b21
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.AUX
@@ -0,0 +1,105 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.AUX 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldbm -lposix
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/share/misc
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do ; rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.BSD43 b/usr.sbin/sendmail/src/Makefile.BSD43
new file mode 100644
index 0000000..4177c3b
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.BSD43
@@ -0,0 +1,123 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This is based on work from Jim Oldroyd -- I believe he was
+# using a fairly old Mt Xinu port.
+#
+# It should also work on UMIPS-BSD from MIPS, if you still have
+# any lying around.
+#
+# @(#)Makefile.BSD43 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DoldBSD43
+
+# see also conf.h for additional compilation flags
+
+# include directories
+#INCDIRS=-I/usr/sww/include/db
+
+# library directories
+#LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldbm -lresolv -ll
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE= unistd.h stddef.h stdlib.h dirent.h sys/time.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+unistd.h stddef.h stdlib.h sys/time.h:
+ cp /dev/null $@
+
+sys/time.h: sys
+
+sys:
+ mkdir sys
+
+dirent.h:
+ echo "#include <sys/dir.h>" > dirent.h
+ echo "#define dirent direct" >> dirent.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.BSDI b/usr.sbin/sendmail/src/Makefile.BSDI
new file mode 100644
index 0000000..898de3e
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.BSDI
@@ -0,0 +1,32 @@
+# @(#)Makefile.BSDI 8.1 (Berkeley) 2/26/94
+
+PROG= sendmail
+DBMDEF= -DNEWDB
+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
+DPADD= ${LIBUTIL} ${LIBKVM}
+LDADD= -lutil -lkvm
+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
+BINGRP= kmem
+BINMODE=6555
+
+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.CLIX b/usr.sbin/sendmail/src/Makefile.CLIX
new file mode 100644
index 0000000..7e54e36
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.CLIX
@@ -0,0 +1,115 @@
+#
+# This makefile is for clipper-based Intergraph systems running CLIX.
+# It and the defines supporting it in the source tree should be considered
+# alpha-quality and used at own risk.
+#
+# Porting done for CICNet, Inc., on behalf the Michigan State Department
+# of Natural Resources.
+#
+# --Paul Southworth <pauls@cic.net>
+#
+# @(#)Makefile.CLIX 8.1 (Berkeley) 4/12/94
+#
+
+# make sure the shell constructs below use the right shell
+SHELL= /bin/sh
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+CC= gcc
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DCLIX
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS= -I/usr/include
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -lnsl -lbsd
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD= getusershell.o
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/bin/newaliases ${DESTDIR}/usr/bin/mailq
+BINOWN= root
+BINGRP= mail
+BINMODE=6555
+INSTALL=cp
+
+ALL= sendmail # aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail #install-docs
+
+install-sendmail: sendmail
+ #${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ ${INSTALL} sendmail ${BINDIR}
+ chmod ${BINMODE} ${BINDIR}/sendmail
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ #${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ # ${STDIR}/sendmail.st
+ ${INSTALL} /dev/null ${STDIR}/sendmail.st
+ #${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+ ${INSTALL} sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail #aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.ConvexOS b/usr.sbin/sendmail/src/Makefile.ConvexOS
new file mode 100644
index 0000000..7bf7450
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.ConvexOS
@@ -0,0 +1,105 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on CxOS 11.0 beta 1 and 10.x.
+#
+# @(#)Makefile.ConvexOS 8.3 (Berkeley) 4/11/94
+#
+
+
+# use O=-O (usual) or O=-g (debugging)
+O= -g -tm c1 -D__STDC__ -d non_int_bit_field
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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 -DYPCOMPAT -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+#INCDIRS=-I/usr/sww/include/db
+
+# library directories
+#LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS=
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.DGUX b/usr.sbin/sendmail/src/Makefile.DGUX
new file mode 100644
index 0000000..d7f63af
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.DGUX
@@ -0,0 +1,101 @@
+#
+# Tested on DG/UX 5.4.2 by A. Bryan Curnutt <bryan@Stoner.COM>.
+#
+# @(#)Makefile.DGUX 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=-DDGUX
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldbm
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/bin
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/etc
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= bin
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Dell b/usr.sbin/sendmail/src/Makefile.Dell
new file mode 100644
index 0000000..39bc1e8
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Dell
@@ -0,0 +1,113 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# Based on a Makefile for Dell SVR4 Issue 2.2 from Kimmo Suominen
+# <kim@grendel.lut.fi> -- I haven't tested this myself. It may
+# work on other SVR4 ports.
+#
+# @(#)Makefile.Dell 8.3 (Berkeley) 4/11/94
+#
+
+# make sure the shell constructs below use the right shell
+SHELL= /bin/sh
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O2
+
+CC= gcc
+#DESTDIR=/usr/local/sendmail
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include NIS support
+# The really old (V7) DBM library is no longer supported.
+# See READ_ME for a description of how these flags interact.
+#
+DBMDEF= -DNEWDB -DNDBM
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -D__svr4__
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -ldb -ldbm -lresolv -lsocket -lnsl -lelf
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/ucblib
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/usr/ucblib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/ucblib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= mail
+BINMODE=6555
+INSTALL=/usr/ucb/install
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.DomainOS b/usr.sbin/sendmail/src/Makefile.DomainOS
new file mode 100644
index 0000000..5564ecb
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.DomainOS
@@ -0,0 +1,123 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on DomainOS 10.3.5
+#
+# @(#)Makefile.DomainOS 8.5 (Berkeley) 4/12/94
+#
+#
+
+# 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.
+# If YPCOMPAT is defined and /var/yp/Makefile exists, sendmail will build
+# both the NEWDB and DBM libraries (the DBM just for YP).
+#
+
+DBMDEF= -DNDBM
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+# You might want to use the BIND 4.9 resolver library here
+#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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE= unistd.h dirent.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. -A nansi $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+unistd.h:
+ cp /dev/null unistd.h
+
+dirent.h:
+ echo "#include <sys/dir.h>" > dirent.h
+ echo "#define dirent direct" >> dirent.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Dynix b/usr.sbin/sendmail/src/Makefile.Dynix
new file mode 100644
index 0000000..344a9b7
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Dynix
@@ -0,0 +1,113 @@
+#
+# Tested on Dynix 3.2.0.
+#
+# From Jim Davis <jdavis@cs.arizona.edu>.
+#
+# ``There is no strtol in libc (well there is in the 'att universe'
+# libc, but I couldn't figure out how to link that in), so I
+# got the Chris Torek strtol.c from bsd-sources on uunet and
+# compiled that. There is no native ndbm either; I couldn't
+# get db 1.72 to pass it's regression test, so I used gdbm-1.7
+# instead. I compiled it with gcc 1.40a. The -lseq is to pick
+# up getopt.''
+#
+# @(#)Makefile.Dynix 8.3 (Berkeley) 4/11/94
+#
+
+CC= gcc
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O -g
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -lseq -lgdbm
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=strtol.o
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= staff # no kmem group,
+BINMODE=4555 # so not setgid
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.FreeBSD b/usr.sbin/sendmail/src/Makefile.FreeBSD
new file mode 100644
index 0000000..e86ff59
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.FreeBSD
@@ -0,0 +1,50 @@
+#
+# Makefile for FreeBSD
+#
+# @(#)Makefile.FreeBSD 8.1 (Berkeley) 2/26/94
+
+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
+
+# FreeBSD 1.0 RELEASE has uname(2) now. Use -DUSEUNAME in order to use it.
+CFLAGS+=-I${.CURDIR} ${DBMDEF} -DMIME -DUSEUNAME
+
+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
+DPADD=
+LDADD= $(LIBUTIL)
+#
+# FreeBSD 1.0 RELEASE has GNU man and doesn't need preformatted man pages anymore
+# (assuming you consider a slower "man" command a feature)
+#
+MAN1= mailq.1 newaliases.1
+MAN5= aliases.5
+MAN8= sendmail.8
+LINKS= /usr/sbin/sendmail /usr/bin/newaliases \
+ /usr/sbin/sendmail /usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+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.HP-UX b/usr.sbin/sendmail/src/Makefile.HP-UX
new file mode 100644
index 0000000..cebc499
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.HP-UX
@@ -0,0 +1,105 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on HP-UX 8.07 on 7xx series.
+#
+# @(#)Makefile.HP-UX 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+# +O is OK on 7xx, and 300xx at 9.0
+O= +O1
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -ldbm
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/bin/newaliases ${DESTDIR}/usr/bin/mailq
+BINOWN= root
+BINGRP= mail
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ cpset sendmail ${BINDIR} ${BINMODE} ${BINOWN} ${BINGRP}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ cpset /dev/null ${STDIR}/sendmail.st 644 ${BINOWN} ${BINGRP}
+ cpset sendmail.hf ${HFDIR} 444 ${BINOWN} ${BINGRP}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.IRIX b/usr.sbin/sendmail/src/Makefile.IRIX
new file mode 100644
index 0000000..30e8f1c
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.IRIX
@@ -0,0 +1,109 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on IRIX 4.0.4.
+#
+# @(#)Makefile.IRIX 8.4 (Berkeley) 4/11/94
+#
+SHELL= /bin/sh
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+CC=gcc
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB (requires -ldb)
+# -DNIS -- include NIS support (requires -lsun)
+# The really old (V7) DBM library is no longer supported.
+# See READ_ME for a description of how these flags interact.
+#
+DBMDEF= -DNDBM
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DIRIX
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -lmld
+#LIBS= -lsun -ldb -lmld
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/bsd/newaliases ${DESTDIR}/usr/bsd/mailq
+BINOWN= root
+BINGRP= sys
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -u ${BINOWN} -g ${BINGRP} -m ${BINMODE} -f ${BINDIR} sendmail
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ cp /dev/null ${STDIR}/sendmail.st
+ chmod 644 ${STDIR}/sendmail.st
+ chown ${BINOWN} ${STDIR}/sendmail.st
+ chgrp ${BINGRP} ${STDIR}/sendmail.st
+ install -u ${BINOWN} -g ${BINGRP} -m 444 -f ${HFDIR} sendmail.hf
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Linux b/usr.sbin/sendmail/src/Makefile.Linux
new file mode 100644
index 0000000..3c8f3e5
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Linux
@@ -0,0 +1,120 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on Linux 0.99p10.
+#
+# Linux doesn't really have standard places to install things, so this
+# Makefile is likely to require a lot of customization. Read it over
+# carefully before proceeding.
+#
+# @(#)Makefile.Linux 8.7 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/local/include
+
+# library directories
+LIBDIRS=-L/usr/local/lib
+
+# libraries required on your system
+LIBS= -lndbm
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# 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
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/bin/newaliases ${DESTDIR}/usr/bin/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+unistd.h:
+ cp /dev/null unistd.h
+
+dirent.h:
+ echo "#include <sys/dir.h>" > dirent.h
+ echo "#define dirent direct" >> dirent.h
+
+NROFF= nroff
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ cp /dev/null ${STDIR}/sendmail.st
+ chmod 644 ${STDIR}/sendmail.st
+ chown ${BINOWN} ${STDIR}/sendmail.st
+ chgrp ${BINGRP} ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Mach386 b/usr.sbin/sendmail/src/Makefile.Mach386
new file mode 100644
index 0000000..eaed6ca
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Mach386
@@ -0,0 +1,107 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.Mach386 8.3 (Berkeley) 4/11/94
+#
+
+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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -ldbm
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.NCR3000 b/usr.sbin/sendmail/src/Makefile.NCR3000
new file mode 100644
index 0000000..a556951
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.NCR3000
@@ -0,0 +1,109 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# NCR 3000 support from Kevin Darcy <kevin@tech.mis.cfc.com>.
+#
+# @(#)Makefile.NCR3000 8.2 (Berkeley) 4/16/94
+#
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DNCR3000
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/ucbinclude
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/ucblib
+
+# libraries required on your system
+LIBS= -lsocket -lc -lelf -lucb -ldbm -lnet -lnsl
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/ucblib
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/var/ucblib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/ucblib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+INSTALL=install
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.NeXT b/usr.sbin/sendmail/src/Makefile.NeXT
new file mode 100644
index 0000000..de0dc7f
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.NeXT
@@ -0,0 +1,114 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on NeXT 2.1.
+#
+# @(#)Makefile.NeXT 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DNeXT -DNETINFO
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# library directories
+LIBDIRS=-L/usr/local/lib
+
+# libraries required on your system
+LIBS= -ldbm
+
+# 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/sendmail
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE= unistd.h dirent.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+unistd.h:
+ cp /dev/null unistd.h
+
+dirent.h:
+ echo "#include <sys/dir.h>" > dirent.h
+ echo "#define dirent direct" >> dirent.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.NetBSD b/usr.sbin/sendmail/src/Makefile.NetBSD
new file mode 100644
index 0000000..ebeacd0
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.NetBSD
@@ -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.OSF1 b/usr.sbin/sendmail/src/Makefile.OSF1
new file mode 100644
index 0000000..c79b2bb
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.OSF1
@@ -0,0 +1,109 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on OSF/1 1.3
+#
+# @(#)Makefile.OSF1 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -Olimit 1000
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# library directories
+LIBDIRS=-L/usr/sww/lib -L/usr/shlib -L/usr/lib
+
+# libraries required on your system
+LIBS= -ldbm
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/var/adm/sendmail
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/share/lib
+
+# additional .o files needed
+OBJADD=
+
+# additional link flags
+#LDADD= -non_shared
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${BINDIR}/newaliases ${BINDIR}/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDADD} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ installbsd -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ cp /dev/null ${STDIR}/sendmail.st
+ chmod 644 ${STDIR}/sendmail.st
+ chown ${BINOWN}.${BINGRP} ${STDIR}/sendmail.st
+ installbsd -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+ rm -f /usr/sbin/smtpd
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.PTX b/usr.sbin/sendmail/src/Makefile.PTX
new file mode 100644
index 0000000..f27238b
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.PTX
@@ -0,0 +1,114 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# For Sequent DYNIX/ptx.
+#
+# From Tim "Pinball Wizard" Wright <timw@sequent.com>.
+#
+# @(#)Makefile.PTX 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -g
+
+# define the database mechanisms available for map & alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+#INCDIRS=-I/usr/sww/include/db
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+#LIBDIRS=-L/usr/sww/lib
+LIBDIRS=
+
+# libraries required on your system
+#LIBS= -ldb -ldbm
+LIBS= -lsocket -linet -lnsl -lseq
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/bin/newaliases ${DESTDIR}/usr/bin/mailq
+BINOWN= root
+BINGRP= sys
+BINMODE=6555
+
+ALL= sendmail aliases.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: $& ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+INSTALL=install
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.RISCos b/usr.sbin/sendmail/src/Makefile.RISCos
new file mode 100644
index 0000000..b4c4b36
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.RISCos
@@ -0,0 +1,117 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# For Mips RISC/os 4.52.
+#
+# @(#)Makefile.RISCos 8.3 (Berkeley) 4/11/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+# be sure we are compiling in BSD mode
+CC= cc -systype bsd43
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DRISCOS -Olimit 800
+
+# see also conf.h for additional compilation flags
+
+# include directories
+#INCDIRS=-I/usr/sww/include/db
+
+# library directories
+#LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -lmld
+
+# 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
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE= stdlib.h dirent.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+stdlib.h:
+ cp /dev/null $@
+
+dirent.h:
+ echo "#include <sys/dir.h>" > dirent.h
+ echo "#define dirent direct" >> dirent.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.SCO b/usr.sbin/sendmail/src/Makefile.SCO
new file mode 100644
index 0000000..f1e7316
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.SCO
@@ -0,0 +1,104 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on SCO.
+#
+# @(#)Makefile.SCO 8.4 (Berkeley) 4/12/94
+#
+
+# 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
+# -DNIS -- include NIS support
+# The really old (V7) DBM library is no longer supported.
+# See READ_ME for a description of how these flags interact.
+#
+DBMDEF=
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -D_SCO_unix_
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -lsocket
+
+# 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}/usr/lib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.SVR4 b/usr.sbin/sendmail/src/Makefile.SVR4
new file mode 100644
index 0000000..92de6dd
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.SVR4
@@ -0,0 +1,113 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# Based on a Makefile for Dell SVR4 Issue 2.2 from Kimmo Suominen
+# <kim@grendel.lut.fi> -- I haven't tested this myself. It may
+# work on other SVR4 ports.
+#
+# @(#)Makefile.SVR4 8.3 (Berkeley) 4/11/94
+#
+
+# make sure the shell constructs below use the right shell
+SHELL= /bin/sh
+
+# use O=-O (usual) or O=-g (debugging)
+O= -O
+
+CC= gcc
+#DESTDIR=/usr/local/sendmail
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include NIS support
+# The really old (V7) DBM library is no longer supported.
+# See READ_ME for a description of how these flags interact.
+#
+DBMDEF= -DNEWDB -DNDBM
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -D__svr4__
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -ldb -ldbm -lresolv -lsocket -lnsl -lelf
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/ucblib
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/usr/ucblib
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/ucblib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= mail
+BINMODE=6555
+INSTALL=/usr/ucb/install
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Solaris b/usr.sbin/sendmail/src/Makefile.Solaris
new file mode 100644
index 0000000..cf359e6
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Solaris
@@ -0,0 +1,115 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on Solaris 2.1 and 2.2.
+#
+# @(#)Makefile.Solaris 8.5 (Berkeley) 4/12/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+# warning: do not use -O with gcc
+O=
+
+CC= gcc
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+# include -DSOLARIS_2_3 for version 2.3 and higher
+ENVDEF= -DSOLARIS
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -lresolv -lsocket -lnsl -lelf
+
+# 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}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/etc/mail
+
+# additional .o files needed
+OBJADD=
+
+# things to be made before compilation begins
+BEFORE= sysexits.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= sys
+BINMODE=6555
+INSTALL=/usr/ucb/install
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+sysexits.h: /usr/ucbinclude/sysexits.h
+ ln -s /usr/ucbinclude/sysexits.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.SunOS b/usr.sbin/sendmail/src/Makefile.SunOS
new file mode 100644
index 0000000..ee3025f
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.SunOS
@@ -0,0 +1,111 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on SunOS 4.1.[12].
+# For SunOS 4.0.3, add -DSUNOS403 to the ENVDEF macro, and
+# create empty files stdlib.h and stddef.h in your
+# compile directory.
+#
+# @(#)Makefile.SunOS 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+# need to add -DSUNOS403 if you are on a SunOS 4.0.3 system
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS= -Bstatic
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -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
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.SunOS.4.0.3 b/usr.sbin/sendmail/src/Makefile.SunOS.4.0.3
new file mode 100644
index 0000000..126ac64
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.SunOS.4.0.3
@@ -0,0 +1,113 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# You may find you need to find versions of some routines
+# such as strcasecmp in order to link this on SunOS 4.0.3.
+#
+# @(#)Makefile.SunOS.4.0.3 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DSUNOS403
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS= -Bstatic
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -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
+
+# additional .o files needed
+OBJADD=
+
+BEFORE= stdlib.h stddef.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+stddef.h stdlib.h:
+ cp /dev/null $@
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.SunOS.5.x b/usr.sbin/sendmail/src/Makefile.SunOS.5.x
new file mode 100644
index 0000000..d40f9dd
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.SunOS.5.x
@@ -0,0 +1,115 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on Solaris 2.3.
+#
+# @(#)Makefile.SunOS.5.x 8.5 (Berkeley) 4/12/94
+#
+
+# use O=-O (usual) or O=-g (debugging)
+# warning: do not use -O with gcc
+O=
+
+CC= gcc
+
+# define the database mechanism used for alias lookups:
+# -DNDBM -- use new DBM
+# -DNEWDB -- use new Berkeley DB
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+# include -DSOLARIS_2_3 for version 2.3 and higher
+ENVDEF= -DSOLARIS_2_3
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -lresolv -lsocket -lnsl -lelf
+
+# 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}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/etc/mail
+
+# additional .o files needed
+OBJADD=
+
+# things to be made before compilation begins
+BEFORE= sysexits.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= sys
+BINMODE=6555
+INSTALL=/usr/ucb/install
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${OBJS} ${LIBDIRS} ${LIBS}
+
+sysexits.h: /usr/ucbinclude/sysexits.h
+ ln -s /usr/ucbinclude/sysexits.h
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Titan b/usr.sbin/sendmail/src/Makefile.Titan
new file mode 100644
index 0000000..89b156a
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Titan
@@ -0,0 +1,114 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.Titan 8.3 (Berkeley) 4/11/94
+#
+
+# put the compiler in BSD mode
+CC= cc -43
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -ldbm
+
+# 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}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/share/misc
+
+# additional .o files needed
+OBJADD=
+
+# additional pseudo-sources needed
+BEFORE= stddef.h stdlib.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+stddef.h stdlib.h:
+ cp /dev/null $@
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.ULTRIX b/usr.sbin/sendmail/src/Makefile.ULTRIX
new file mode 100644
index 0000000..a3f222e
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.ULTRIX
@@ -0,0 +1,107 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on Ultrix 4.2A and 4.3A.
+#
+# @(#)Makefile.ULTRIX 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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 -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -Olimit 800
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb
+
+# 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}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.UMAX b/usr.sbin/sendmail/src/Makefile.UMAX
new file mode 100644
index 0000000..c69e2b6
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.UMAX
@@ -0,0 +1,114 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# This has been tested on Encore UMAX V
+#
+# @(#)Makefile.UMAX 8.3 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include NIS support
+# The really old (V7) DBM library is no longer supported.
+# See READ_ME for a description of how these flags interact.
+#
+DBMDEF= -DNIS
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF= -DUMAXV
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=
+
+# libraries required on your system
+LIBS= -lyp -lrpc
+
+# 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}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/lib
+
+# additional .o files needed
+OBJADD=
+
+# things to do before compilation
+BEFORE= stddef.h
+
+stddef.h:
+ echo "#define _STDDEF_H" > stddef.h
+ chmod 444 stddef.h
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ install -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ install -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ install -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/Makefile.Utah b/usr.sbin/sendmail/src/Makefile.Utah
new file mode 100644
index 0000000..84ee571
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.Utah
@@ -0,0 +1,40 @@
+# @(#)Makefile.Utah 8.1 (Berkeley) 2/26/94
+
+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 -DNDBM -DOLD_NEWDB
+
+CFLAGS+=-I${.CURDIR} ${DBMDEF} -Dsetpgid=setpgrp
+
+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
+DPADD= ${LIBDBM} ${LIBCOMPAT}
+LDADD=
+MAN1= mailq.0 newaliases.0
+MAN5= aliases.0
+MAN8= sendmail.0
+LINKS= ${DESTDIR}/usr/sbin/sendmail ${DESTDIR}/usr/bin/newaliases \
+ ${DESTDIR}/usr/sbin/sendmail ${DESTDIR}/usr/bin/mailq
+BINDIR= /usr/sbin
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+beforeinstall:
+ 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.dist b/usr.sbin/sendmail/src/Makefile.dist
new file mode 100644
index 0000000..5fab596
--- /dev/null
+++ b/usr.sbin/sendmail/src/Makefile.dist
@@ -0,0 +1,107 @@
+#
+# This Makefile is designed to work on the old "make" program. It does
+# not use the obj subdirectory. It also does not install documentation
+# automatically -- think of it as a quick start for sites that have the
+# old make program (I recommend that you get and port the new make if you
+# are going to be doing any signficant work on sendmail).
+#
+# @(#)Makefile.dist 8.12 (Berkeley) 4/11/94
+#
+
+# 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
+# -DNIS -- include 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
+
+# environment definitions (e.g., -D_AIX3)
+ENVDEF=
+
+# see also conf.h for additional compilation flags
+
+# include directories
+INCDIRS=-I/usr/sww/include/db
+
+# loader options
+LDOPTS=
+
+# library directories
+LIBDIRS=-L/usr/sww/lib
+
+# libraries required on your system
+LIBS= -ldb -ldbm
+
+# location of sendmail binary (usually /usr/sbin or /usr/lib)
+BINDIR= ${DESTDIR}/usr/sbin
+
+# location of sendmail.st file (usually /var/log or /usr/lib)
+STDIR= ${DESTDIR}/var/log
+
+# location of sendmail.hf file (usually /usr/share/misc or /usr/lib)
+HFDIR= ${DESTDIR}/usr/share/misc
+
+# additional .o files needed
+OBJADD=
+
+################### end of user configuration flags ######################
+
+CFLAGS= -I. $O ${INCDIRS} ${DBMDEF} ${ENVDEF}
+
+OBJS= alias.o arpadate.o clock.o collect.o conf.o convtime.o daemon.o \
+ deliver.o domain.o envelope.o err.o headers.o macro.o main.o \
+ map.o mci.o parseaddr.o queue.o readcf.o recipient.o \
+ savemail.o srvrsmtp.o stab.o stats.o sysexits.o \
+ trace.o udb.o usersmtp.o util.o version.o ${OBJADD}
+
+LINKS= ${DESTDIR}/usr/ucb/newaliases ${DESTDIR}/usr/ucb/mailq
+BINOWN= root
+BINGRP= kmem
+BINMODE=6555
+
+ALL= sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+all: ${ALL}
+
+sendmail: ${BEFORE} ${OBJS}
+ ${CC} -o sendmail ${LDOPTS} ${OBJS} ${LIBDIRS} ${LIBS}
+
+NROFF= nroff -h
+
+aliases.0: aliases.5
+ ${NROFF} -mandoc aliases.5 > aliases.0
+
+mailq.0: mailq.1
+ ${NROFF} -mandoc mailq.1 > mailq.0
+
+newaliases.0: newaliases.1
+ ${NROFF} -mandoc newaliases.1 > newaliases.0
+
+sendmail.0: sendmail.8
+ ${NROFF} -mandoc sendmail.8 > sendmail.0
+
+INSTALL=install
+
+install: install-sendmail install-docs
+
+install-sendmail: sendmail
+ ${INSTALL} -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} sendmail ${BINDIR}
+ for i in ${LINKS}; do rm -f $$i; ln -s ${BINDIR}/sendmail $$i; done
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 644 /dev/null \
+ ${STDIR}/sendmail.st
+ ${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 sendmail.hf ${HFDIR}
+
+# doesn't actually install them -- you may want to install pre-nroff versions
+install-docs: aliases.0 mailq.0 newaliases.0 sendmail.0
+
+clean:
+ rm -f ${OBJS} sendmail aliases.0 mailq.0 newaliases.0 sendmail.0
+
+# dependencies
+# gross overkill, and yet still not quite enough....
+${OBJS}: sendmail.h conf.h
diff --git a/usr.sbin/sendmail/src/READ_ME b/usr.sbin/sendmail/src/READ_ME
new file mode 100644
index 0000000..cc0b419
--- /dev/null
+++ b/usr.sbin/sendmail/src/READ_ME
@@ -0,0 +1,872 @@
+# 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 (Berkeley) 4/17/94
+#
+
+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.
+
+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, last update 4/17/94 07:05:32)
diff --git a/usr.sbin/sendmail/src/TODO b/usr.sbin/sendmail/src/TODO
new file mode 100644
index 0000000..80d35d0
--- /dev/null
+++ b/usr.sbin/sendmail/src/TODO
@@ -0,0 +1,287 @@
+(Version 8.22 of 3/12/94)
+
+Key:
+ X -- extension (user visible change)
+ B -- bug fix
+ S -- security fix
+ E -- enhancement to existing algorithm
+
+
+X **** 8 -> 7 bit MIME conversion.
+
+E **** Change NoReturn to be an envelope flag. [8.7]
+
+X **** Add M_NOLOOPBACKCHK (k) mailer flag to turn off check of name in
+ HELO command. [8.8]
+
+X **** Merge Sun changes. [8.7]
+
+X **** Macro giving size of the message in bytes.
+
+X **** Create a "service switch" abstraction that will interface with
+ Sun NSS, Ultrix /etc/svc.conf, etc. This will allow you to
+ turn off DNS entirely, a la ``OIoff''. [8.7]
+
+X **** Should have new mailer flags to override LocalMailer stuff:
+ - M_ALIASABLE (A) -- can use as the LHS of an alias.
+ - M_HASPWENT (w) -- should have a /etc/passwd entry. If not found
+ there, implies user unknown. Also implies .forward and UDB
+ searching, search for |, /, and :include:, etc.).
+ - Actually, UDB searching and |, /, and :include: mapping should
+ probably be on another flag. (Cannot be 'l' for back compat
+ reasons.)
+ - Need for $@host part of triple and Return-Receipt-To: processing
+ should also be split apart.
+ [8.8]
+
+X **** Mailer flag to enable/disable surrounding route-addrs with
+ angle brackets in setsender(). UUCP cleanup scripts treat
+ these as file redirection.
+
+X **** Mailer flag to override MX lookups.
+
+E **** Fix parseaddr to return a dummy mailer with QBADADDR set for
+ all cases except null input; change calls to be more sceptical
+ about the return value, checking this bit instead of just
+ checking for == NULL. (Eric Wassenaar) [8.7]
+
+X **** Run time configurable locking -- e.g., compile in HASFLOCK and
+ HASLOCKF, and then choose at runtime between these.
+
+B **** Aliases with .REDIRECT fail during newaliases if the "n" flag
+ is given. Problem is, sometimes you want them to, sometimes
+ you don't. Perhaps two flavors of "error" mailer?
+
+B **** Calls to gethostbyname with a trailing dot fail if you are
+ not running DNS.
+
+E **** Move delivery forking from sendenvelope to sendall so that
+ the connection cache works between split envelopes, and to
+ avoid a flurry of processes should you be sending to lots of
+ sub-lists.
+
+X **** Add uucp-bang mailer that strips off any domain name from
+ the envelope recipient address first; this is for use in
+ mailer table entries.
+
+X **** "quote" map (inverse of dequote). Lets you turn node::user
+ into "node::user"@DECNET.gateway
+
+X **** Named rulesets.
+
+? **** Should $( [1.2.3.4] $) convert the address to a name?
+
+E **** Change collect() handling to use high level timeouts instead
+ of per-line timeouts -- the current mechanism is swamping
+ the machine with system calls. (Look at KJS code.)
+
+E *** Long term host status -- store host status on disk for sharing
+ between runs.
+
+X *** Extend I option to allow setting of retry and timeout values.
+ drl@vuse.vanderbilt.edu (David R. Linn).
+
+X *** Total connection cache lifespan timeout -- a way to give a
+ timeout on connections regardless of whether they are active
+ or not. For single threaded servers such as Microsoft SMTP
+ gateway. Douglas Anderson <dlander@afterlife.ncsc.mil>.
+
+X *** Mailer flag that does a "ping" equivalent -- if it fails, wait
+ 30 seconds and try again (for dialup PPP connections). Could
+ just try the connection and then immediately retry on some
+ kinds of failures.
+
+X *** Create a macro that has message size.
+ Peter Wemm <peter@DIALix.oz.au>
+
+E *** Dynamically allocate MAXNAME buffers for headers.
+
+E *** Dynamically allocate "line" buffer in readaliases().
+
+X *** Add ability to disable Return-Receipt-To: on a privacy flag. [8.8]
+
+X *** Add -P to set precedence (e.g., -Pbulk). [8.8] (BCX)
+
+X *** Runtime option to enable/disable IDENT protocol.
+
+E *** Don't send ErrMsgFile to postmaster bounces. (Josh Smith,
+ josh@osiris.ac.hmc.edu).
+
+X *** Add "user" map to look up a user name via getpwnam -- so that
+ non-local names can be forwarded to another site. [8.8]
+
+E *** Have daemons that start up check the alias database for
+ correctness and auto-rebuild if necessary. This is to handle
+ the case of a system crash during an alias database rebuild.
+
+E *** Eliminate E qf line and e_errorqueue; use e_errorsto a la
+ e_receiptto. This simplifies and gives symmetry. (Eric
+ Wassenaar)
+
+X *** DECNET_RELAY support in configs.
+
+X *** -wN command line flag to set the width of mailq output.
+ (Allan Johannesen)
+
+E *** Move mailertable lookup after UUCP-specific class checks?
+ (Kimmo Suominen <kim@tac.nyc.ny.us>)
+
+E *** Users in more than one list with different owners get duplicate
+ deliveries -- maybe just assign them arbitrarily to one
+ envelope or the other?
+
+X ** Make MAXBADCOMMANDS run time configurable.
+
+E ** Allow mailertable entries of the form ``error:message''.
+
+X ** Have .forward files re-queue if the home directory isn't
+ accessible? On some option...
+ (Q.G.Campbell@newcastle.ac.uk)
+
+X ** Have local delivery queue if NIS is down? On some option...
+ (Q.G.Campbell@newcastle.ac.uk)
+
+E ** Have nullclient configuration resolve local names to the local
+ mailer and then redirect them in ruleset 5; this allows you to
+ redirect root differently depending on the client. It's not
+ clear this is really a good idea though.
+
+E ** Move CurHostAddr into mci struct, and make CurMCI variable
+ point to this, so that logging will give the correct address
+ instead of (0) for cached connections. Motonori Nakamura.
+
+X ** Allow use of a generalized network service for aliasing?
+ How would the protocol be defined?
+ James Gritton <gritton@byu.edu>.
+
+E ** Make "local configuration error" a temporary failure?
+ (add EX_CONFIG to the markfailure list)
+
+X ** (sigh) BSMTP.
+
+X ** "E" configuration line that sets environment variables.
+
+E ** Change listen() high-load backoff to accept and issue a 4xx
+ message so that it responds more quickly.
+
+E ** Change "/usr/tmp/dead.letter" to be based on _PATH_VARTMP.
+
+B ** Commas in NAME envariable cause problems (Peter Wan
+ <peter@cc.gatech.edu>). Merge with suggestions to use
+ MIME-format for 8-bit characters?
+
+E ** Save address information that comes back as the "additional
+ records" part of an MX lookup, to avoid additional name server
+ attempts. If there is an MX record without an additional A
+ record, delete it (this avoids a problem with misconfigured
+ DNS situations).
+
+X ** Allow a way to extend the $Z macro with local configuration
+ information.
+
+X ** Allow $x in -bt mode to expand macro "x". (BCX) [8.8]
+
+X ** Allow /address in -bt mode to expand address through ruleset 0,
+ aliases, etc. and display results. [8.8]
+
+X ** "R mailer address" in -bt mode does remotename on address.
+
+E ** Adjust "infinite loop in rule" code to handle entire ruleset
+ (Code from Michael Corrigan).
+
+E ** Allow :include: from command line (not SMTP) to assist in
+ "personal list" management -- i.e., creating lists that
+ cannot be EXPNed.
+
+X ** Database (keyed lookup) auto-rebuild.
+
+X ** Find a good test suite and include in the distribution.
+
+S ** You can use symbolic links to point into protected directories.
+ (AEJ)
+
+X ** Extend OI to allow separate settings for canonification, MX, and A
+ lookups. [8.8?]
+
+X ** Add $!x class to match any number of words not in class x. (KRE)
+
+X ** LOCAL_RULE_5 (Spencer Sun, spencer@phoenix.Princeton.EDU)
+
+X ** Add "bestmx" map -- returns "best MX host" for this address.
+ Allows you to do automatic detection of when you are the best
+ MX for a given address. [8.7?]
+
+X ** Some way to diddle resolver flags on a per-lookup basis, such
+ as a flag to the map declaration. (Rick McCarty)
+ - Is this really a good idea? DNSRCH can be turned off by
+ putting a dot at the end. AAONLY?
+
+X ** Extend makemap to "gather" values -- i.e., merge entries that
+ have the same keys. [8.8] (BCX)
+
+E ** Allow error messages on individual addresses in the qf file.
+ (BCX)
+
+X ** Multi-character option names. [9.1]
+
+X ** User database extensions for mailing lists:
+ list:precedence -- Precedence: value for new message
+ list:envelopefrom -- envelope "from" value for new message
+ others? [8.8]
+
+X ** Command line switch to set precedence (for mailing list
+ generation). (BCX)
+
+B ** Restore `T' line to eliminate X-Authentication-Warning: at
+ inappropriate times. (Christophe Wolfhugel)
+ - T could become a shorthand for Ct -- i.e., create a new
+ predefined class.
+ - Eliminate "<user> set sender to <address>" message entirely?
+ (this is the workaround)
+
+B ** Return-Path: header should have <> added if not already there.
+
+X ** Add heuristic to determine if other end is a sendmail; use
+ that to decide whether or not to honor F=I mailer flag.
+ [der Mouse <mouse@collatz.mcrcim.mcgill.edu>]
+
+X ** Automatically drop into MIME mode if you have a full name
+ with 8-bit characters. See envelope.c 8.19.1.1 and util.c
+ 8.17.1.1. From Anders Ellefsrud <anders@ifi.uio.no>.
+
+X ** -b? flag to read a header and show you what it will look like
+ after all rewriting for an indicated address.
+
+E ** Log $u in logsender() (for=<someaddress>).
+
+B ** Include SOCKADDR in MCI struct for logging (currently gives
+ a sockaddr of zero when printing from the cache).
+
+X ** Allow option to set the characters that are autoquoted in
+ addresses?
+
+X * Map that does MB/MR lookups. Rick McCarty <mccarty@io.com>.
+
+X * Allow $> anywhere in RHS. John Boeske <jboeske@ualberta.ca>.
+
+X * -V flag to print state of all (?) compilation flags.
+
+X * Handle Expires: header field (if still in queue).
+
+X * WIN/3B support (non-atomic rename, no h_addr_list, others?)
+ (Bruce Lilly <blilly!bruce@uu.psi.com>)
+
+X * Sun YBTS daemon uses -ba. [Martin Kiff <MGK@newton.npl.co.uk>]
+
+B * EXPN adds @domain to all mailers, including prog. Is this right?
+ [Bob Henry]
+
+B * EXPN adds @localhost instead of @$M. [Pel Emanuelsson]
+
+E * Change body put code to time out around individual puts. This will
+ make the timeout algorithm more responsive and more resilient.
+ Unfortunately, it's also a pain in the butt.
+
+X * Some way to relay unfound local users to another site.
+
+X * Disable all default RW sets except mailer-specific?
diff --git a/usr.sbin/sendmail/src/TRACEFLAGS b/usr.sbin/sendmail/src/TRACEFLAGS
new file mode 100644
index 0000000..f05c219
--- /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 0000000..9952db5
--- /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.5 b/usr.sbin/sendmail/src/aliases.5
new file mode 100644
index 0000000..f40f64d
--- /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 0000000..d3f9ac5
--- /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/clock.c b/usr.sbin/sendmail/src/clock.c
new file mode 100644
index 0000000..45ef1c2
--- /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 0000000..b77f6e9
--- /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 0000000..8c7ad33
--- /dev/null
+++ b/usr.sbin/sendmail/src/conf.c
@@ -0,0 +1,2381 @@
+/*
+ * 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 (Berkeley) 4/18/94";
+#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(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 "/kernel"
+# 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 __FreeBSD__
+# undef PS_STRINGS /* XXX This is broken due to needing<machine/pmap.h> */
+# 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; /* character checked for validity */
+char *optarg; /* 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();
+
+ 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];
+
+ 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
+
+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 0000000..0f02692
--- /dev/null
+++ b/usr.sbin/sendmail/src/conf.h
@@ -0,0 +1,1191 @@
+/*
+ * 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 */
+# ifdef __NetBSD__
+# define HASUNAME 1 /* has uname(2) syscall */
+# 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 0000000..5cb5e49
--- /dev/null
+++ b/usr.sbin/sendmail/src/convtime.c
@@ -0,0 +1,197 @@
+/*
+ * 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 <ctype.h>
+# include "useful.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 0000000..293438b
--- /dev/null
+++ b/usr.sbin/sendmail/src/daemon.c
@@ -0,0 +1,1547 @@
+/*
+ * 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 (Berkeley) 4/18/94 (with daemon mode)";
+#else
+static char sccsid[] = "@(#)daemon.c 8.48 (Berkeley) 4/18/94 (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] == '[')
+ {
+ long hid;
+ register char *p = strchr(host, ']');
+
+ if (p != NULL)
+ {
+ *p = '\0';
+#ifdef NETINET
+ hid = inet_addr(&host[1]);
+ if (hid == -1)
+#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*/
+ addr.sin.sin_addr.s_addr = hid;
+#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;
+#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(hbuf, "%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", hbuf);
+
+ /* send query */
+ if (write(s, hbuf, strlen(hbuf)) < 0)
+ goto closeident;
+
+ /* get result */
+ i = read(s, hbuf, sizeof hbuf);
+ (void) close(s);
+ clrevent(ev);
+ if (i <= 0)
+ goto noident;
+ if (hbuf[--i] == '\n' && hbuf[--i] == '\r')
+ i--;
+ hbuf[++i] = '\0';
+
+ if (tTd(9, 3))
+ printf("getauthinfo: got %s\n", hbuf);
+
+ /* parse result */
+ p = strchr(hbuf, ':');
+ 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 */
+ (void) sprintf(hbuf, "%s@%s",
+ p, 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;
+ u_long 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';
+ in_addr = inet_addr(&name[1]);
+
+ /* nope -- ask the name server */
+ hp = gethostbyaddr((char *)&in_addr, sizeof(struct 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 0000000..4266122
--- /dev/null
+++ b/usr.sbin/sendmail/src/deliver.c
@@ -0,0 +1,2409 @@
+/*
+ * 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.82 (Berkeley) 4/18/94";
+#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;
+ 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_OSERR;
+ 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;
+
+ /* 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], 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
+ {
+ Errors++;
+ usrerr(statmsg, errstring(errno));
+ }
+
+ /*
+ ** 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);
+
+ 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;
+ MCI mcibuf;
+
+ (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;
+ mode = stb.st_mode;
+
+ /* limit the errors to those actually caused in the child */
+ errno = 0;
+ ExitStat = EX_OK;
+
+ if (bitset(0111, stb.st_mode))
+ exit(EX_CANTCREAT);
+ 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, O_WRONLY|O_CREAT|O_APPEND, FileMode);
+ if (f == NULL)
+ {
+ message("554 cannot open: %s", errstring(errno));
+ 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 0000000..48109fe
--- /dev/null
+++ b/usr.sbin/sendmail/src/domain.c
@@ -0,0 +1,769 @@
+/*
+ * 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 (Berkeley) 3/11/94 (with name server)";
+#else
+static char sccsid[] = "@(#)domain.c 8.19 (Berkeley) 3/11/94 (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;
+
+ /* this may be an MX suppression-style address */
+ p = strchr(MXHostBuf, ']');
+ if (p != NULL)
+ {
+ *p = '\0';
+ if (inet_addr(&MXHostBuf[1]) != -1)
+ *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;
+ 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 0000000..3a2314c
--- /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 (Berkeley) 4/14/94";
+#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, "w");
+ 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 0000000..c6a87e9
--- /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 0000000..8493e79c
--- /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 0000000..8a8a90b
--- /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 0000000..f7b9da4
--- /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 0000000..0164d91
--- /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 0000000..e2af9df
--- /dev/null
+++ b/usr.sbin/sendmail/src/main.c
@@ -0,0 +1,1479 @@
+/*
+ * 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 (Berkeley) 4/15/94";
+#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, "FS=", 3) == 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.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 */
+ CurEnv->e_bodytype = newstr(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(optarg);
+ 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 (*optarg != '\0')
+ define('r', newstr(optarg), CurEnv);
+ if (p != NULL && *p != '\0')
+ define('s', newstr(p), 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 */
+ 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");
+ }
+
+ /*
+ ** 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;
+ }
+
+ /* 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 0000000..7c13db9
--- /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 0000000..01ba411
--- /dev/null
+++ b/usr.sbin/sendmail/src/map.c
@@ -0,0 +1,1339 @@
+/*
+ * 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 (Berkeley) 4/17/94";
+#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.
+**
+** Side Effects:
+** none.
+*/
+
+struct rwbuf
+{
+ int rwb_len; /* size of buffer */
+ char *rwb_buf; /* ptr to buffer */
+};
+
+struct rwbuf RwBufs[2]; /* buffers for rewriting output */
+
+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;
+ register struct rwbuf *rwb;
+ int i;
+ int len;
+
+ 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");
+ }
+
+ rwb = RwBufs;
+ if (av == NULL)
+ rwb++;
+
+ /* 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 (rwb->rwb_len < ++len)
+ {
+ /* need to malloc additional space */
+ rwb->rwb_len = len;
+ if (rwb->rwb_buf != NULL)
+ free(rwb->rwb_buf);
+ rwb->rwb_buf = xalloc(rwb->rwb_len);
+ }
+
+ bp = rwb->rwb_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", rwb->rwb_buf);
+ return rwb->rwb_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 0000000..8160b83
--- /dev/null
+++ b/usr.sbin/sendmail/src/mci.c
@@ -0,0 +1,398 @@
+/*
+ * 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.13 (Berkeley) 4/12/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();
+
+ if (MaxMciCache <= 0)
+ {
+ /* we don't support caching */
+ return;
+ }
+
+ /*
+ ** Find the best slot. This may cause expired connections
+ ** to be closed.
+ */
+
+ mcislot = mci_scan(mci);
+
+ /* 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 (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;
+
+#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 */
+ 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 0000000..c611b78
--- /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 0000000..00621c2
--- /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 0000000..a611c0b
--- /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 0000000..efedb72
--- /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 (Berkeley) 4/18/94 (with queueing)";
+#else
+static char sccsid[] = "@(#)queue.c 8.41 (Berkeley) 4/18/94 (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", e->e_message);
+
+ /* 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", p);
+ if ((p = macvalue('s', e)) != NULL)
+ fprintf(tfp, "$s%s\n", p);
+ if ((p = macvalue('_', e)) != NULL)
+ fprintf(tfp, "$_%s\n", p);
+
+ /* output name of sender */
+ fprintf(tfp, "S%s\n", e->e_from.q_paddr);
+
+ /* 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", q->q_paddr);
+ }
+ }
+
+ /* 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", q->q_paddr);
+ 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, a->q_paddr);
+}
+
+ /*
+** 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)
+# 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 0000000..bd902c0
--- /dev/null
+++ b/usr.sbin/sendmail/src/readcf.c
@@ -0,0 +1,1681 @@
+/*
+ * 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 (Berkeley) 3/18/94";
+#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 */
+ define(val[0], newstr(&val[1]), 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;
+ }
+ 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 0000000..c6c15c4
--- /dev/null
+++ b/usr.sbin/sendmail/src/recipient.c
@@ -0,0 +1,1059 @@
+/*
+ * 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 (Berkeley) 2/28/94";
+#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;
+ char *oldto = e->e_to;
+
+ 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;
+
+ for (p = list; *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;
+ 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 0000000..6467def
--- /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.28 (Berkeley) 3/11/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", 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 0000000..ee0f700
--- /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 binmail 1 ,
+.Xr mail 1 ,
+.Xr rmail 1 ,
+.Xr syslog 3 ,
+.Xr aliases 5 ,
+.Xr mailaddr 7 ,
+.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 0000000..4a42b2c
--- /dev/null
+++ b/usr.sbin/sendmail/src/sendmail.h
@@ -0,0 +1,973 @@
+/*
+ * 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 (Berkeley) 4/14/94
+ */
+
+/*
+** SENDMAIL.H -- Global definitions for sendmail.
+*/
+
+# ifdef _DEFINE
+# define EXTERN
+# ifndef lint
+static char SmailSccsId[] = "@(#)sendmail.h 8.43 4/14/94";
+# 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 *));
+
+/* 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 0000000..142a7f5
--- /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 0000000..eef525d
--- /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 0000000..07893e5
--- /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 0000000..2dc6827
--- /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 0000000..fff3783
--- /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/trace.c b/usr.sbin/sendmail/src/trace.c
new file mode 100644
index 0000000..29421ee
--- /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 0000000..7887cb3
--- /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 0000000..ba33a79
--- /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 0000000..06acd3f
--- /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 0000000..10b3fb4
--- /dev/null
+++ b/usr.sbin/sendmail/src/util.c
@@ -0,0 +1,1467 @@
+/*
+ * 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 (Berkeley) 4/14/94";
+#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;
+}
diff --git a/usr.sbin/sendmail/src/version.c b/usr.sbin/sendmail/src/version.c
new file mode 100644
index 0000000..fa3c31a
--- /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.9.1 (Berkeley) 4/18/94";
+#endif /* not lint */
+
+char Version[] = "8.6.9";
diff --git a/usr.sbin/sliplogin/Makefile b/usr.sbin/sliplogin/Makefile
new file mode 100644
index 0000000..2299e65
--- /dev/null
+++ b/usr.sbin/sliplogin/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 7/19/93
+
+PROG= sliplogin
+MAN8= sliplogin.8
+BINOWN= root
+BINMODE=4555
+INSTALLFLAGS=-fschg
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/sliplogin/pathnames.h b/usr.sbin/sliplogin/pathnames.h
new file mode 100644
index 0000000..9e792a3
--- /dev/null
+++ b/usr.sbin/sliplogin/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.1 (Berkeley) 6/6/93
+ */
+
+#ifndef COMPAT
+#include <paths.h>
+#else
+#define _PATH_DEVNULL "/dev/null"
+#endif
+
+#define _PATH_ACCESS "/etc/sliphome/slip.hosts"
+#define _PATH_LOGIN "/etc/sliphome/slip.login"
+#define _PATH_LOGOUT "/etc/sliphome/slip.logout"
+#define _PATH_DEBUG "/tmp/sliplogin.XXXXXX"
+
diff --git a/usr.sbin/sliplogin/slip.hosts b/usr.sbin/sliplogin/slip.hosts
new file mode 100644
index 0000000..f6ebf40
--- /dev/null
+++ b/usr.sbin/sliplogin/slip.hosts
@@ -0,0 +1,11 @@
+# @(#)slip.hosts 8.1 (Berkeley) 6/6/93
+#
+# login local-addr remote-addr mask opt1 opt2
+# (normal,compress,noicmp)
+#
+Schez vangogh chez 0xffffff00 compress
+Sjun vangogh 128.32.130.36 0xffffff00 normal
+Sleconte vangogh leconte 0xffffff00 compress
+Sleeb vangogh leeb 0xffffff00 compress
+Smjk vangogh pissaro-sl 0xffffff00 compress
+Soxford vangogh oxford 0xffffff00 compress
diff --git a/usr.sbin/sliplogin/slip.login b/usr.sbin/sliplogin/slip.login
new file mode 100644
index 0000000..3c70095
--- /dev/null
+++ b/usr.sbin/sliplogin/slip.login
@@ -0,0 +1,12 @@
+#!/bin/sh -
+#
+# @(#)slip.login 8.1 (Berkeley) 6/6/93
+
+#
+# generic login file for a slip line. sliplogin invokes this with
+# the parameters:
+# 1 2 3 4 5 6 7-n
+# slipunit ttyspeed loginname local-addr remote-addr mask opt-args
+#
+/sbin/ifconfig sl$1 inet $4 $5 netmask $6
+exit
diff --git a/usr.sbin/sliplogin/sliplogin.8 b/usr.sbin/sliplogin/sliplogin.8
new file mode 100644
index 0000000..1c71988
--- /dev/null
+++ b/usr.sbin/sliplogin/sliplogin.8
@@ -0,0 +1,220 @@
+.\" Copyright (c) 1990, 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.
+.\"
+.\" @(#)sliplogin.8 8.2 (Berkeley) 1/5/94
+.\"
+.Dd January 5, 1994
+.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 0000000..d8af959
--- /dev/null
+++ b/usr.sbin/sliplogin/sliplogin.c
@@ -0,0 +1,384 @@
+/*-
+ * 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[] = "@(#)sliplogin.c 8.2 (Berkeley) 2/1/94";
+#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/signal.h>
+#include <sys/file.h>
+#include <sys/syslog.h>
+#include <netdb.h>
+
+#if BSD >= 199006
+#define POSIX
+#endif
+#ifdef POSIX
+#include <sys/termios.h>
+#include <sys/ioctl.h>
+#include <ttyent.h>
+#else
+#include <sgtty.h>
+#endif
+#include <net/slip.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.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) {
+ (void)fprintf(stderr, "sliplogin: %s: %s\n",
+ _PATH_ACCESS, strerror(errno));
+ syslog(LOG_ERR, "%s: %m\n", _PATH_ACCESS);
+ exit(1);
+ }
+ 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;
+ }
+ (void)fprintf(stderr, "SLIP access denied for %s\n", name);
+ syslog(LOG_ERR, "SLIP access denied for %s\n", name);
+ exit(4);
+ /* NOTREACHED */
+}
+
+char *
+sigstr(s)
+ int s;
+{
+ static char buf[32];
+
+ switch (s) {
+ case SIGHUP: return("HUP");
+ case SIGINT: return("INT");
+ case SIGQUIT: return("QUIT");
+ case SIGILL: return("ILL");
+ case SIGTRAP: return("TRAP");
+ case SIGIOT: return("IOT");
+ case SIGEMT: return("EMT");
+ case SIGFPE: return("FPE");
+ case SIGKILL: return("KILL");
+ case SIGBUS: return("BUS");
+ case SIGSEGV: return("SEGV");
+ case SIGSYS: return("SYS");
+ case SIGPIPE: return("PIPE");
+ case SIGALRM: return("ALRM");
+ case SIGTERM: return("TERM");
+ case SIGURG: return("URG");
+ case SIGSTOP: return("STOP");
+ case SIGTSTP: return("TSTP");
+ case SIGCONT: return("CONT");
+ case SIGCHLD: return("CHLD");
+ case SIGTTIN: return("TTIN");
+ case SIGTTOU: return("TTOU");
+ case SIGIO: return("IO");
+ case SIGXCPU: return("XCPU");
+ case SIGXFSZ: return("XFSZ");
+ case SIGVTALRM: return("VTALRM");
+ case SIGPROF: return("PROF");
+ case SIGWINCH: return("WINCH");
+#ifdef SIGLOST
+ case SIGLOST: return("LOST");
+#endif
+ case SIGUSR1: return("USR1");
+ case SIGUSR2: return("USR2");
+ }
+ (void)sprintf(buf, "sig %d", s);
+ return(buf);
+}
+
+void
+hup_handler(s)
+ int s;
+{
+ char logoutfile[MAXPATHLEN];
+
+ seteuid(0);
+ (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() == -1)
+ 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(0, TIOCSCTTY, (caddr_t)0) == -1)
+ perror("ioctl (TIOCSCTTY)");
+#endif
+ } else {
+ extern char *getlogin();
+
+ if ((name = getlogin()) == NULL) {
+ (void) fprintf(stderr, "access denied - no username\n");
+ syslog(LOG_ERR, "access denied - getlogin returned 0\n");
+ exit(1);
+ }
+ findid(name);
+ }
+ (void) fchmod(0, 0600);
+ (void) fprintf(stderr, "starting slip login for %s\n", loginname);
+#ifdef POSIX
+ /* set up the line parameters */
+ if (tcgetattr(0, &tios) < 0) {
+ syslog(LOG_ERR, "tcgetattr: %m");
+ exit(1);
+ }
+ otios = tios;
+ cfmakeraw(&tios);
+ tios.c_iflag &= ~IMAXBEL;
+ if (tcsetattr(0, TCSAFLUSH, &tios) < 0) {
+ syslog(LOG_ERR, "tcsetattr: %m");
+ exit(1);
+ }
+ speed = cfgetispeed(&tios);
+#else
+ /* set up the line parameters */
+ if (ioctl(0, 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(0, TIOCSETP, (caddr_t)&tty) < 0) {
+ syslog(LOG_ERR, "ioctl (TIOCSETP): %m");
+ exit(1);
+ }
+#endif
+ /* find out what ldisc we started with */
+ if (ioctl(0, TIOCGETD, (caddr_t)&odisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCGETD) (1): %m");
+ exit(1);
+ }
+ ldisc = SLIPDISC;
+ if (ioctl(0, TIOCSETD, (caddr_t)&ldisc) < 0) {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
+ exit(1);
+ }
+ /* find out what unit number we were assigned */
+ if (ioctl(0, 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(0, TIOCSETD, (caddr_t)&odisc);
+ exit(6);
+ }
+
+ /* reset uid to users' to allow the user to give a signal. */
+ seteuid(uid);
+ /* twiddle thumbs until we get a signal */
+ while (1)
+ sigpause(0);
+
+ /* NOTREACHED */
+}
diff --git a/usr.sbin/slstat/Makefile b/usr.sbin/slstat/Makefile
new file mode 100644
index 0000000..de18bc8
--- /dev/null
+++ b/usr.sbin/slstat/Makefile
@@ -0,0 +1,11 @@
+# from: @(#)Makefile 5.6 (Berkeley) 4/23/91
+# $Id: Makefile,v 1.1 1993/11/16 04:16:46 brezak Exp $
+
+PROG= slstat
+MAN8= slstat.8
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/slstat/slstat.8 b/usr.sbin/slstat/slstat.8
new file mode 100644
index 0000000..0194cbf
--- /dev/null
+++ b/usr.sbin/slstat/slstat.8
@@ -0,0 +1,141 @@
+.\" 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.
+.\"
+.\" @(#)slstat.8 6.8 (Berkeley) 6/20/91
+.\"
+.TH SLSTAT 1 "June 20, 1991"
+.UC 4
+.SH NAME
+slstat \- report serial line IP statistics
+.SH SYNOPSIS
+.nf
+.ft B
+slstat [ \-i interval ] [ \-v ] [ \-r ] [ unit ] [ system ] [ core ]
+.ft R
+.fi
+.SH DESCRIPTION
+.I Slstat
+reports certain kernel statistics kept about serial line internet
+protocol traffic.
+.PP
+The options are as follows:
+.TP
+\-i
+Repeat the display indefinitely every
+.I interval
+seconds.
+If no
+.I interval
+is specified, the default is 5 seconds.
+.TP
+\-v
+Verbose display of extra fields of information.
+.TP
+\-r
+Display all values in rate per second that ammount per interval.
+.TP
+unit
+is a single digit specifying the slip interface. The default unit is
+.I 0
+for interface
+.I sl0.
+.TP
+system
+Extract the name list from the specified system instead of the default, /386bsd.
+.TP
+core
+Extract values associated with the name list from the specified
+core instead of the default, /dev/kmem.
+.PP
+By default,
+.I vmstat
+displays the following information:
+.PP
+.TP
+in
+bytes received
+.TP
+out
+bytes sent
+.TP
+pack
+packets received or sent
+.TP
+comp
+compressed packets received or sent
+.TP
+uncomp
+uncompressed packets received or sent
+.TP
+unknwn
+inbound packets of unknown type
+.TP
+toss
+inbound packets tossed because of error
+.TP
+other
+all other inbound or outbound ip packets
+.TP
+err
+input or output errors
+.TP
+search
+searches for connection state
+.TP
+miss
+times we could not find a connectoin state
+.TP
+coll
+collisions with end of clists.
+If you get many collisions (more than one or two
+a day) you probably do not have enough clists
+and you should increase "nclist" in param.c.
+.SH EXAMPLES
+The command ``slstat -i 5'' will print what the system is doing every five
+seconds.
+.SH FILES
+.ta \w'/dev/kmem 'u
+/386bsd default kernel namelist
+.br
+/dev/kmem default memory file
+.SH SEE ALSO
+.IR fstat (1),
+.IR netstat (1),
+.IR nfsstat (1),
+.IR ps (1),
+.IR systat (1),
+.IR iostat (8),
+.IR pstat (8)
+.sp
+The sections starting with ``Interpreting system activity'' in
+.IR "Installing and Operating 4.3BSD" .
+.SH BUGS
+
diff --git a/usr.sbin/slstat/slstat.c b/usr.sbin/slstat/slstat.c
new file mode 100644
index 0000000..fe41c79
--- /dev/null
+++ b/usr.sbin/slstat/slstat.c
@@ -0,0 +1,287 @@
+/*
+ * print serial line IP statistics:
+ * slstat [-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[] = "$Id: slstat.c,v 1.1 1993/11/16 04:16:48 brezak Exp $";
+#endif
+
+#include <stdio.h>
+#include <paths.h>
+#include <nlist.h>
+#include <kvm.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 = NULL;
+
+int kflag;
+int rflag;
+int vflag;
+unsigned interval = 5;
+int unit;
+
+extern char *malloc();
+extern off_t lseek();
+
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int c;
+ --argc; ++argv;
+ while (argc > 0) {
+ if (strcmp(argv[0], "-v") == 0) {
+ ++vflag;
+ ++argv, --argc;
+ continue;
+ }
+ if (strcmp(argv[0], "-r") == 0) {
+ ++rflag;
+ ++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 (kvm_openfiles(system, kmemf, NULL) < 0) {
+ (void)fprintf(stderr,
+ "slstat: kvm_openfiles(%s,%s,0): %s\n",
+ system, kmemf, kvm_geterr());
+ exit(1);
+ }
+ if ((c = kvm_nlist(nl)) != 0) {
+ if (c > 0) {
+ (void)fprintf(stderr,
+ "slstat: undefined symbols in %s:", system);
+ for (c = 0; c < sizeof(nl)/sizeof(nl[0]); c++)
+ if (nl[c].n_type == 0)
+ fprintf(stderr, " %s", nl[c].n_name);
+ (void)fputc('\n', stderr);
+ } else
+ (void)fprintf(stderr, "slstat: kvm_nlist: %s\n",
+ kvm_geterr());
+ exit(1);
+ }
+ intpr();
+ exit(0);
+}
+
+#define V(offset) ((line % 20)? ((sc->offset - osc->offset) / (rflag ? interval : 1)) : sc->offset)
+#define AMT (sizeof(*sc) - 2 * sizeof(sc->sc_comp.tstate))
+
+usage()
+{
+ static char umsg[] =
+ "usage: slstat [-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", "unknwn");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s",
+ "toss", "other", "err");
+ printf(" | %8.8s %6.6s %6.6s %6.6s %6.6s",
+ "out", "pack", "comp", "uncomp", "other");
+ if (vflag)
+ printf(" %6.6s %6.6s %6.6s %6.6s",
+ "search", "miss", "err", "coll");
+ putchar('\n');
+ }
+ printf("%8u %6d %6u %6u %6u",
+ V(sc_bytesrcvd),
+ 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 %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),
+ V(sc_if.if_ierrors));
+ printf(" | %8u %6d %6u %6u %6u",
+ V(sc_bytessent) / (rflag ? interval : 1),
+ 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 %6u %6u",
+ V(sc_comp.sls_searches),
+ V(sc_comp.sls_misses),
+ V(sc_if.if_oerrors),
+ V(sc_if.if_collisions));
+ 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>
+
+int 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_openfiles(system, kmemf, (void *)0);
+ if (kd == 0)
+ 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(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((char *)addr, buf, size) != size)
+ return -1;
+ return 0;
+}
diff --git a/usr.sbin/swapinfo/Makefile b/usr.sbin/swapinfo/Makefile
new file mode 100644
index 0000000..0802582
--- /dev/null
+++ b/usr.sbin/swapinfo/Makefile
@@ -0,0 +1,12 @@
+# @(#)Makefile 5.5 (Berkeley) 4/23/91
+
+PROG= swapinfo
+SRCS= swapinfo.c devname.c # getbsize.c
+.PATH: ${.CURDIR}/../../bin/df
+
+DPADD= ${LIBMATH} ${LIBUTIL}
+LDADD= -lm -lkvm
+BINGRP= kmem
+BINMODE=2555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/swapinfo/README b/usr.sbin/swapinfo/README
new file mode 100644
index 0000000..f8019a8
--- /dev/null
+++ b/usr.sbin/swapinfo/README
@@ -0,0 +1,38 @@
+swapinfo
+========
+
+Swapinfo is designed to provide some information to the user about the
+state of the swap space on the system. I've written it based on a
+brief (!) perusal of the VM code in 386BSD. I could be pretty confused
+about how it all fits together, and perhaps this is totally bogus.
+It seems to work for me, though.
+
+How it works:
+
+During startup, the system traverses the list of configured swap partitions,
+and determines the size of the various partitions. As each new partition
+is added for swapping (via swapon), the free space on that disk is added
+to a linked list of free space. Adjacent areas are coalesced to form
+larger areas. The swapping algorithm seems to take the first free section
+that it finds [?].
+
+Swapinfo reads in the list of configured swap partitions from the /dev/kmem,
+to determine the size of the partitions. It then traverses the list
+of free space, figuring up how much is still available and how much
+has therefore been used. Things get a little hairy in that the swap space
+is divided amongst the configured swap partitions so that the first
+4096 blocks of swap go on the first swap partition, the second 4096 on
+the second swap partition, and so on. This works out to be a fairly
+simple bit of code, though.
+
+More caveats:
+
+This works on my system. Your milage may vary. Since I'm reading /dev/kmem
+to follow a linked list, the program could easily get lost looking for
+some free space if anything got changed between reads of /dev/kmem.
+If you get occasional inconsistant results, ignore 'em.
+
+Feel free to send bug reports, flames, etc., to:
+
+Kevin Lahey
+kml@rokkaku.atl.ga.us
diff --git a/usr.sbin/swapinfo/devname.c b/usr.sbin/swapinfo/devname.c
new file mode 100644
index 0000000..5f2815d
--- /dev/null
+++ b/usr.sbin/swapinfo/devname.c
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)devname.c 5.14 (Berkeley) 5/6/91";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <db.h>
+#include <stdio.h>
+#include <paths.h>
+
+char *
+devname(dev, type)
+ dev_t dev;
+ mode_t type;
+{
+ struct {
+ mode_t type;
+ dev_t dev;
+ } bkey;
+ static DB *db;
+ static int failure;
+ DBT data, key;
+
+ if (!db && !failure &&
+ !(db = dbopen(_PATH_DEVDB, O_RDONLY, 0, DB_HASH, NULL))) {
+ (void)fprintf(stderr,
+ "warning: no device database %s\n", _PATH_DEVDB);
+ failure = 1;
+ }
+ if (failure)
+ return("??");
+
+ /*
+ * 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.
+ */
+ bkey.dev = dev;
+ bkey.type = type;
+ key.data = &bkey;
+ key.size = sizeof(bkey);
+ return((db->get)(db, &key, &data, 0L) ? "??" : (char *)data.data);
+}
diff --git a/usr.sbin/swapinfo/swapinfo.1 b/usr.sbin/swapinfo/swapinfo.1
new file mode 100644
index 0000000..54e89c5
--- /dev/null
+++ b/usr.sbin/swapinfo/swapinfo.1
@@ -0,0 +1,53 @@
+.\"
+.\" swapinfo
+.\"
+.Dd February 23, 1993
+.Dt SWAPINFO 1
+.Sh NAME
+.Nm swapinfo
+.Nd display free swap space
+.Sh SYNOPSIS
+.Nm swapinfo
+.Op Fl k
+.Sh DESCRIPTION
+.Nm Swapinfo
+displays statistics about the amount of free swap space on all of the
+swap areas compiled into the kernel.
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl k
+By default, all sizes are reported in 512-byte block counts.
+The
+.Fl k
+option causes the numbers to be reported in kilobyte counts.
+.El
+.Sh STATISTICS
+Statistics are reported for all swap partitions configured 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.
+.Sh "BUGS AND CAVEATS"
+The information reported by
+.Nm swapinfo
+is stored in the kernel in a linked list. Since we are merely reading
+this list out of kernel memory, it is entirely possible that the list could
+change as we try to read it. Suspicious and unrepeatable values are probably
+incorrect.
+.Pp
+Statistics are reported for all swap partitions compiled into the kernel,
+regardless of whether those partitions are being used.
+.Sh AUTHOR
+.RS
+Kevin Lahey
+.br
+kml@rokkaku.atl.ga.us
diff --git a/usr.sbin/swapinfo/swapinfo.c b/usr.sbin/swapinfo/swapinfo.c
new file mode 100644
index 0000000..1e39a68
--- /dev/null
+++ b/usr.sbin/swapinfo/swapinfo.c
@@ -0,0 +1,225 @@
+/*
+ * swapinfo
+ *
+ * Swapinfo will provide some information about the state of the swap
+ * space for the system. It'll determine the number of swap areas,
+ * their original size, and their utilization.
+ *
+ * Kevin Lahey, February 16, 1993
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <sys/stat.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/buf.h>
+#include <sys/conf.h>
+#include <sys/rlist.h>
+#include <nlist.h>
+#include <kvm.h>
+
+struct rlist *swapmap;
+
+static struct nlist nl[] = {{"_swapmap"}, /* list of free swap areas */
+#define VM_SWAPMAP 0
+ {"_swdevt"}, /* list of swap devices and sizes */
+#define VM_SWDEVT 1
+ {"_nswap"}, /* size of largest swap device */
+#define VM_NSWAP 2
+ {"_nswdev"}, /* number of swap devices */
+#define VM_NSWDEV 3
+ {"_dmmax"}, /* maximum size of a swap block */
+#define VM_DMMAX 4
+ {""}};
+
+char *getbsize __P((int *, long *));
+void usage __P((void));
+
+main (argc, argv)
+int argc;
+char **argv;
+{
+ int i, total_avail, total_free, total_partitions, *by_device,
+ nswap, nswdev, dmmax, ch;
+ struct swdevt *swdevt;
+ struct rlist head;
+ static long blocksize;
+ static int headerlen;
+ static char *header;
+ char **save;
+ kvm_t *kd;
+
+ /* We are trying to be simple here: */
+
+ save = argv;
+ while ((ch = getopt(argc, argv, "k")) != EOF)
+ switch(ch) {
+ case 'k':
+ putenv("BLOCKSIZE=1k");
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argv += optind;
+
+ if (!*argv) {
+ argv = save;
+ argv[0] = ".";
+ argv[1] = NULL;
+ }
+
+ /* Open up /dev/kmem for reading. */
+
+ if ((kd = kvm_openfiles(NULL, NULL, NULL, NULL, NULL)) == (kvm_t *)0) {
+ fprintf (stderr, "%s: kvm_openfiles: %s\n",
+ argv [0], kvm_geterr(kd));
+ exit (1);
+ }
+
+ /* Figure out the offset of the various structures we'll need. */
+
+ if (kvm_nlist(kd, nl) == -1) {
+ fprintf (stderr, "%s: kvm_nlist: %s\n",
+ argv [0], kvm_geterr(kd));
+ exit (1);
+ }
+
+ if (kvm_read(kd, nl[VM_NSWAP].n_value, &nswap, sizeof (nswap)) !=
+ sizeof (nswap)) {
+ fprintf (stderr, "%s: didn't read all of nswap\n",
+ argv [0]);
+ exit (5);
+ }
+
+ if (kvm_read(kd, nl[VM_NSWDEV].n_value, &nswdev, sizeof (nswdev)) !=
+ sizeof (nswdev)) {
+ fprintf (stderr, "%s: didn't read all of nswdev\n",
+ argv [0]);
+ exit (5);
+ }
+
+ if (kvm_read(kd, nl[VM_DMMAX].n_value, &dmmax, sizeof (dmmax)) !=
+ sizeof (dmmax)) {
+ fprintf (stderr, "%s: didn't read all of dmmax\n",
+ argv [0]);
+ exit (5);
+ }
+
+ if ((swdevt = malloc (sizeof (struct swdevt) * nswdev)) == NULL ||
+ (by_device = calloc (sizeof (*by_device), nswdev)) == NULL) {
+ perror ("malloc");
+ exit (5);
+ }
+
+ if (kvm_read(kd, nl[VM_SWDEVT].n_value, swdevt,
+ sizeof (struct swdevt) * nswdev) !=
+ sizeof (struct swdevt) * nswdev) {
+ fprintf (stderr, "%s: didn't read all of swdevt\n",
+ argv [0]);
+ exit (5);
+ }
+
+ if (kvm_read(kd, nl[0].n_value, &swapmap, sizeof (struct rlist *)) !=
+ sizeof (struct rlist *)) {
+ fprintf (stderr, "%s: didn't read all of swapmap\n",
+ argv [0]);
+ exit (5);
+ }
+
+ /* Traverse the list of free swap space... */
+
+ total_free = 0;
+ while (swapmap) {
+ int top, bottom, next_block;
+
+ if (kvm_read(kd, (long) swapmap, &head, sizeof (struct rlist )) !=
+ sizeof (struct rlist )) {
+ fprintf (stderr, "%s: didn't read all of head\n",
+ argv [0]);
+ exit (5);
+ }
+
+ top = head.rl_end;
+ bottom = head.rl_start;
+
+ total_free += top - bottom + 1;
+
+ /*
+ * Swap space is split up among the configured disk.
+ * The first dmmax blocks of swap space some from the
+ * first disk, the next dmmax blocks from the next,
+ * and so on. 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.
+ */
+
+ while (top / dmmax != bottom / dmmax) {
+ next_block = ((bottom + dmmax) / dmmax);
+ by_device [(bottom / dmmax) % nswdev] +=
+ next_block * dmmax - bottom;
+ bottom = next_block * dmmax;
+ }
+
+ by_device [(bottom / dmmax) % nswdev] +=
+ top - bottom + 1;
+
+ swapmap = head.rl_next;
+ }
+
+ header = getbsize(&headerlen, &blocksize);
+ printf ("%-10s %10s %10s %10s %10s\n",
+ "Device", header, "Used", "Available", "Capacity");
+ for (total_avail = total_partitions = i = 0; i < nswdev; i++) {
+ printf ("/dev/%-5s %10d ",
+ devname (swdevt [i].sw_dev, S_IFBLK),
+ swdevt [i].sw_nblks / (blocksize/512));
+
+ /*
+ * Don't report statistics for partitions which have not
+ * yet been activated via swapon(8).
+ */
+
+ if (!swdevt [i].sw_freed) {
+ printf (" *** not available for swapping ***\n");
+ } else {
+ total_partitions++;
+ total_avail += swdevt [i].sw_nblks;
+ printf ("%10d %10d %7.0f%%\n",
+ (swdevt [i].sw_nblks - by_device [i]) / (blocksize/512),
+ by_device [i] / (blocksize/512),
+ (double) (swdevt [i].sw_nblks -
+ by_device [i]) /
+ (double) swdevt [i].sw_nblks * 100.0);
+ }
+ }
+
+ /*
+ * If only one partition has been set up via swapon(8), we don't
+ * need to bother with totals.
+ */
+
+ if (total_partitions > 1)
+ printf ("%-10s %10d %10d %10d %7.0f%%\n", "Total",
+ total_avail / (blocksize/512),
+ (total_avail - total_free) / (blocksize/512),
+ total_free / (blocksize/512),
+ (double) (total_avail - total_free) /
+ (double) total_avail * 100.0);
+
+ exit (0);
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "usage: swapinfo [-k]\n");
+ exit(1);
+}
+
+
diff --git a/usr.sbin/sysctl/Makefile b/usr.sbin/sysctl/Makefile
new file mode 100644
index 0000000..8d94c66
--- /dev/null
+++ b/usr.sbin/sysctl/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sysctl
+MAN8= 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 0000000..4b60ccf
--- /dev/null
+++ b/usr.sbin/sysctl/pathconf.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pathconf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PC_NAMES { \
+ { 0, 0 }, \
+ { "link_max", CTLTYPE_INT }, \
+ { "max_canon", CTLTYPE_INT }, \
+ { "max_input", CTLTYPE_INT }, \
+ { "name_max", CTLTYPE_INT }, \
+ { "path_max", CTLTYPE_INT }, \
+ { "pipe_buf", CTLTYPE_INT }, \
+ { "chown_restricted", CTLTYPE_INT }, \
+ { "no_trunc", CTLTYPE_INT }, \
+ { "vdisable", CTLTYPE_INT }, \
+}
+#define PC_MAXID 10
+
+struct ctlname pcnames[] = PC_NAMES;
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list pclist = { pcnames, PC_MAXID };
+
+int Aflag, aflag, nflag, wflag, stdinflag;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ char *path;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "Aan")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+ path = *argv++;
+ if (strcmp(path, "-") == 0)
+ stdinflag = 1;
+ argc--;
+ if (Aflag || aflag) {
+ listall(path, &pclist);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(path, *argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(path, lp)
+ char *path;
+ struct list *lp;
+{
+ int lvl2;
+
+ if (lp->list == 0)
+ return;
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ parse(path, lp->list[lvl2].ctl_name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into an index.
+ * Lookup and print out the attribute if it exists.
+ */
+parse(pathname, string, flags)
+ char *pathname;
+ char *string;
+ int flags;
+{
+ int indx, value;
+ char *bufp, buf[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((indx = findname(string, "top", &bufp, &pclist)) == -1)
+ return;
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (stdinflag)
+ value = fpathconf(0, indx);
+ else
+ value = pathconf(pathname, indx);
+ if (value == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", value);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n",
+ "pathname [-n] variable ...",
+ "pathname [-n] -a", "pathname [-n] -A");
+ exit(1);
+}
diff --git a/usr.sbin/sysctl/sysctl.8 b/usr.sbin/sysctl/sysctl.8
new file mode 100644
index 0000000..cc8e2df
--- /dev/null
+++ b/usr.sbin/sysctl/sysctl.8
@@ -0,0 +1,214 @@
+.\" 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: @(#)sysctl.8 8.1 (Berkeley) 6/6/93
+.\" $Id$
+.\"
+.Dd September 23, 1994
+.Dt SYSCTL 8
+.Os
+.Sh NAME
+.Nm sysctl
+.Nd get or set kernel state
+.Sh SYNOPSIS
+.Nm sysctl
+.Op Fl n
+.Ar name ...
+.Nm sysctl
+.Op Fl n
+.Fl w
+.Ar name=value ...
+.Nm sysctl
+.Op Fl n
+.Fl aA
+.Sh DESCRIPTION
+The
+.Nm sysctl
+utility retrieves kernel state and allows processes with
+appropriate privilege to set kernel state.
+The state to be retrieved or set is described using a
+``Management Information Base'' (``MIB'') style name,
+described as a dotted set of components.
+The
+.Fl a
+flag can be used to list all the currently available string or integer values.
+The
+.Fl A
+flag will list all the known MIB names including tables.
+Those with string or integer values will be printed as with the
+.Fl a
+flag; for the table values,
+the name of the utility to retrieve them is given.
+.Pp
+The
+.Fl n
+flag specifies that the printing of the field name should be
+suppressed and that only its value should be output.
+This flag is useful for setting shell variables.
+For example, to save the pagesize in variable psize, use:
+.Bd -literal -offset indent -compact
+set psize=`sysctl -n hw.pagesize`
+.Ed
+.Pp
+If just a MIB style name is given,
+the corresponding value is retrieved.
+If a value is to be set, the
+.Fl w
+flag must be specified and the MIB name followed
+by an equal sign and the new value to be used.
+.Pp
+The information available from
+.Nm sysctl
+consists of integers, strings, and tables.
+The tabular information can only be retrieved by special
+purpose programs such as
+.Nm ps ,
+.Nm systat ,
+and
+.Nm netstat .
+The string and integer information is summaried below.
+For a detailed description of these variable see
+.Xr sysctl 3 .
+The changeable column indicates whether a process with appropriate
+privilege can change the value.
+.Bl -column net.inet.ip.forwardingxxxxxx integerxxx
+.It Sy Name Type Changeable
+.It kern.ostype string no
+.It kern.osrelease string no
+.It kern.osrevision integer no
+.It kern.version string no
+.It kern.maxvnodes integer yes
+.It kern.maxproc integer yes
+.It kern.maxfiles integer yes
+.It kern.argmax integer no
+.It kern.securelevel integer raise only
+.It kern.hostname string yes
+.It kern.hostid integer yes
+.It kern.clockrate struct no
+.It kern.posix1version integer no
+.It kern.ngroups integer no
+.It kern.job_control integer no
+.It kern.saved_ids integer no
+.It kern.link_max integer no
+.It kern.max_canon integer no
+.It kern.max_input integer no
+.It kern.name_max integer no
+.It kern.path_max integer no
+.It kern.pipe_buf integer no
+.It kern.chown_restricted integer no
+.It kern.no_trunc integer no
+.It kern.vdisable integer no
+.It kern.boottime struct no
+.It kern.domainname string yes
+.It kern.update integer yes
+.It kern.osreldate string no
+.It kern.bootfile string yes
+.It vm.loadavg struct no
+.It machdep.console_device dev_t no
+.It net.inet.ip.forwarding integer yes
+.It net.inet.ip.redirect integer yes
+.It net.inet.ip.ttl integer yes
+.It net.inet.icmp.maskrepl integer yes
+.It net.inet.udp.checksum integer yes
+.It hw.machine string no
+.It hw.model string no
+.It hw.ncpu integer no
+.It hw.byteorder integer no
+.It hw.physmem integer no
+.It hw.usermem integer no
+.It hw.pagesize integer no
+.It hw.floatingpoint 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 0000000..4dfa6f3
--- /dev/null
+++ b/usr.sbin/sysctl/sysctl.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/gmon.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <vm/vm_param.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct ctlname topname[] = CTL_NAMES;
+struct ctlname kernname[] = CTL_KERN_NAMES;
+struct ctlname vmname[] = CTL_VM_NAMES;
+struct ctlname netname[] = CTL_NET_NAMES;
+struct ctlname hwname[] = CTL_HW_NAMES;
+struct ctlname username[] = CTL_USER_NAMES;
+struct ctlname debugname[CTL_DEBUG_MAXID];
+#ifdef CTL_MACHDEP_NAMES
+struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
+#endif
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list toplist = { topname, CTL_MAXID };
+struct list secondlevel[] = {
+ { 0, 0 }, /* CTL_UNSPEC */
+ { kernname, KERN_MAXID }, /* CTL_KERN */
+ { vmname, VM_MAXID }, /* CTL_VM */
+ { 0, 0 }, /* CTL_FS */
+ { netname, NET_MAXID }, /* CTL_NET */
+ { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
+ { hwname, HW_MAXID }, /* CTL_HW */
+#ifdef CTL_MACHDEP_NAMES
+ { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
+#else
+ { 0, 0 }, /* CTL_MACHDEP */
+#endif
+ { username, USER_MAXID }, /* CTL_USER_NAMES */
+};
+
+int Aflag, aflag, nflag, wflag;
+
+/*
+ * Variables requiring special processing.
+ */
+#define CLOCK 0x00000001
+#define BOOTTIME 0x00000002
+#define CONSDEV 0x00000004
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, lvl1;
+
+ while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ case 'w':
+ wflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (Aflag || aflag) {
+ debuginit();
+ for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
+ listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(*argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(prefix, lp)
+ char *prefix;
+ struct list *lp;
+{
+ int lvl2;
+ char *cp, name[BUFSIZ];
+
+ if (lp->list == 0)
+ return;
+ strcpy(name, prefix);
+ cp = &name[strlen(name)];
+ *cp++ = '.';
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ strcpy(cp, lp->list[lvl2].ctl_name);
+ parse(name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+parse(string, flags)
+ char *string;
+ int flags;
+{
+ int indx, type, state, size, len;
+ int special = 0;
+ void *newval = 0;
+ int intval, newsize = 0;
+ quad_t quadval;
+ struct list *lp;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((cp = strchr(string, '=')) != NULL) {
+ if (!wflag) {
+ fprintf(stderr, "Must specify -w to set variables\n");
+ exit(2);
+ }
+ *strchr(buf, '=') = '\0';
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ }
+ if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
+ return;
+ mib[0] = indx;
+ if (indx == CTL_DEBUG)
+ debuginit();
+ lp = &secondlevel[indx];
+ if (lp->list == 0) {
+ fprintf(stderr, "%s: class is not implemented\n",
+ topname[indx]);
+ return;
+ }
+ if (bufp == NULL) {
+ listall(topname[indx].ctl_name, lp);
+ return;
+ }
+ if ((indx = findname(string, "second", &bufp, lp)) == -1)
+ return;
+ mib[1] = indx;
+ type = lp->list[indx].ctl_type;
+ len = 2;
+ switch (mib[0]) {
+
+ case CTL_KERN:
+ switch (mib[1]) {
+ case KERN_PROF:
+ mib[2] = GPROF_STATE;
+ size = sizeof state;
+ if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
+ if (flags == 0)
+ return;
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stderr,
+ "kernel is not compiled for profiling\n");
+ return;
+ }
+ if (!nflag)
+ fprintf(stdout, "%s: %s\n", string,
+ state == GMON_PROF_OFF ? "off" : "running");
+ return;
+ case KERN_VNODE:
+ case KERN_FILE:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use pstat to view %s information\n", string);
+ return;
+ case KERN_PROC:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use ps to view %s information\n", string);
+ return;
+ case KERN_CLOCKRATE:
+ special |= CLOCK;
+ break;
+ case KERN_BOOTTIME:
+ special |= BOOTTIME;
+ break;
+ }
+ break;
+
+ case CTL_HW:
+ break;
+
+ case CTL_VM:
+ if (mib[1] == VM_LOADAVG) {
+ double loads[3];
+
+ getloadavg(loads, 3);
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout, "%.2f %.2f %.2f\n",
+ loads[0], loads[1], loads[2]);
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use vmstat or systat to view %s information\n", string);
+ return;
+
+ case CTL_NET:
+ if (mib[1] == PF_INET) {
+ len = sysctl_inet(string, &bufp, mib, flags, &type);
+ if (len >= 0)
+ break;
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr, "Use netstat to view %s information\n", string);
+ return;
+
+ case CTL_DEBUG:
+ mib[2] = CTL_DEBUG_VALUE;
+ len = 3;
+ break;
+
+ case CTL_MACHDEP:
+#ifdef CPU_CONSDEV
+ if (mib[1] == CPU_CONSDEV)
+ special |= CONSDEV;
+#endif
+ break;
+
+ case CTL_FS:
+ case CTL_USER:
+ break;
+
+ default:
+ fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
+ return;
+
+ }
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (newsize > 0) {
+ switch (type) {
+ case CTLTYPE_INT:
+ intval = atoi(newval);
+ newval = &intval;
+ newsize = sizeof intval;
+ break;
+
+ case CTLTYPE_QUAD:
+ sscanf(newval, "%qd", &quadval);
+ newval = &quadval;
+ newsize = sizeof quadval;
+ break;
+ }
+ }
+ size = BUFSIZ;
+ if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (special & CLOCK) {
+ struct clockinfo *clkp = (struct clockinfo *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout,
+ "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
+ clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
+ return;
+ }
+ if (special & BOOTTIME) {
+ struct timeval *btp = (struct timeval *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s", string,
+ ctime(&btp->tv_sec));
+ else
+ fprintf(stdout, "%d\n", btp->tv_sec);
+ return;
+ }
+ if (special & CONSDEV) {
+ dev_t dev = *(dev_t *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ devname(dev, S_IFCHR));
+ else
+ fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ switch (type) {
+ case CTLTYPE_INT:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", *(int *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %d -> ", string,
+ *(int *)buf);
+ fprintf(stdout, "%d\n", *(int *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRING:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%s\n", buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %s -> ", string, buf);
+ fprintf(stdout, "%s\n", newval);
+ }
+ return;
+
+ case CTLTYPE_QUAD:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%qd\n", *(quad_t *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %qd -> ", string,
+ *(quad_t *)buf);
+ fprintf(stdout, "%qd\n", *(quad_t *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRUCT:
+ fprintf(stderr, "%s: unknown structure returned\n",
+ string);
+ return;
+
+ default:
+ case CTLTYPE_NODE:
+ fprintf(stderr, "%s: unknown type returned\n",
+ string);
+ return;
+ }
+}
+
+/*
+ * Initialize the set of debugging names
+ */
+debuginit()
+{
+ int mib[3], size, loc, i;
+
+ if (secondlevel[CTL_DEBUG].list != 0)
+ return;
+ secondlevel[CTL_DEBUG].list = debugname;
+ mib[0] = CTL_DEBUG;
+ mib[2] = CTL_DEBUG_NAME;
+ for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
+ mib[1] = i;
+ size = BUFSIZ - loc;
+ if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
+ continue;
+ debugname[i].ctl_name = &names[loc];
+ debugname[i].ctl_type = CTLTYPE_INT;
+ loc += size;
+ }
+}
+
+struct ctlname inetname[] = CTL_IPPROTO_NAMES;
+struct ctlname ipname[] = IPCTL_NAMES;
+struct ctlname icmpname[] = ICMPCTL_NAMES;
+struct ctlname udpname[] = UDPCTL_NAMES;
+struct list inetlist = { inetname, IPPROTO_MAXID };
+struct list inetvars[] = {
+ { ipname, IPCTL_MAXID }, /* ip */
+ { icmpname, ICMPCTL_MAXID }, /* icmp */
+ { 0, 0 }, /* igmp */
+ { 0, 0 }, /* ggmp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* tcp */
+ { 0, 0 },
+ { 0, 0 }, /* egp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* pup */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { udpname, UDPCTL_MAXID }, /* udp */
+};
+
+/*
+ * handle internet requests
+ */
+sysctl_inet(string, bufpp, mib, flags, typep)
+ char *string;
+ char **bufpp;
+ int mib[];
+ int flags;
+ int *typep;
+{
+ struct list *lp;
+ int indx;
+
+ if (*bufpp == NULL) {
+ listall(string, &inetlist);
+ return (-1);
+ }
+ if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
+ return (-1);
+ mib[2] = indx;
+ if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
+ lp = &inetvars[indx];
+ else if (!flags)
+ return (-1);
+ else {
+ fprintf(stderr, "%s: no variables defined for this protocol\n",
+ string);
+ return (-1);
+ }
+ if (*bufpp == NULL) {
+ listall(string, lp);
+ return (-1);
+ }
+ if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
+ return (-1);
+ mib[3] = indx;
+ *typep = lp->list[indx].ctl_type;
+ return (4);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
+ "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
+ "sysctl [-n] -a", "sysctl [-n] -A");
+ exit(1);
+}
diff --git a/usr.sbin/syslogd/Makefile b/usr.sbin/syslogd/Makefile
new file mode 100644
index 0000000..5112bd4
--- /dev/null
+++ b/usr.sbin/syslogd/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= syslogd
+SRCS= syslogd.c ttymsg.c
+.PATH: ${.CURDIR}/../../usr.bin/wall
+MAN5= syslog.conf.5
+MAN8= syslogd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/syslogd/pathnames.h b/usr.sbin/syslogd/pathnames.h
new file mode 100644
index 0000000..2dc61a8
--- /dev/null
+++ b/usr.sbin/syslogd/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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#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 0000000..b19e75d
--- /dev/null
+++ b/usr.sbin/syslogd/syslog.conf.5
@@ -0,0 +1,224 @@
+.\" Copyright (c) 1990, 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.
+.\"
+.\" @(#)syslog.conf.5 8.1 (Berkeley) 6/9/93
+.\"
+.Dd June 9, 1993
+.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 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
diff --git a/usr.sbin/syslogd/syslogd.8 b/usr.sbin/syslogd/syslogd.8
new file mode 100644
index 0000000..09f3ddb
--- /dev/null
+++ b/usr.sbin/syslogd/syslogd.8
@@ -0,0 +1,122 @@
+.\" Copyright (c) 1983, 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.
+.\"
+.\" @(#)syslogd.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.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 0000000..47592d5
--- /dev/null
+++ b/usr.sbin/syslogd/syslogd.c
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1988, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94";
+#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/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/msgbuf.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utmp.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 */
+
+void cfline __P((char *, struct filed *));
+char *cvthname __P((struct sockaddr_in *));
+int decode __P((const char *, CODE *));
+void die __P((int));
+void domark __P((int));
+void fprintlog __P((struct filed *, int, char *));
+void init __P((int));
+void logerror __P((char *));
+void logmsg __P((int, char *, char *, int));
+void printline __P((char *, char *));
+void printsys __P((char *));
+void reapchild __P((int));
+char *ttymsg __P((struct iovec *, int, char *, int));
+void usage __P((void));
+void wallmsg __P((struct filed *, struct iovec *));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch, funix, i, inetm, fklog, klogm, len;
+ struct sockaddr_un sunx, fromunix;
+ struct sockaddr_in sin, frominet;
+ FILE *fp;
+ char *p, line[MSG_BSIZE + 1];
+
+ while ((ch = getopt(argc, argv, "df:m:p:")) != EOF)
+ switch(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) != 0)
+ usage();
+
+ if (!Debug)
+ (void)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 = strchr(LocalHostName, '.')) != NULL) {
+ *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);
+
+#ifndef SUN_LEN
+#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2)
+#endif
+ memset(&sunx, 0, 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, SUN_LEN(&sunx)) < 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);
+ inetm = 0;
+ if (finet >= 0) {
+ struct servent *sp;
+
+ sp = getservbyname("syslog", "udp");
+ if (sp == NULL) {
+ errno = 0;
+ logerror("syslog/udp: unknown service");
+ die(0);
+ }
+ memset(&sin, 0, 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(0);
+ (void)signal(SIGHUP, init);
+
+ for (;;) {
+ int nfds, readfds = FDMASK(funix) | inetm | klogm;
+
+ 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) {
+ line[i] = '\0';
+ printline(cvthname(&frominet), line);
+ } else if (i < 0 && errno != EINTR)
+ logerror("recvfrom inet");
+ }
+ }
+}
+
+void
+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.
+ */
+void
+printline(hname, msg)
+ char *hname;
+ char *msg;
+{
+ int c, pri;
+ char *p, *q, line[MAXLINE + 1];
+
+ /* 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().
+ */
+void
+printsys(msg)
+ char *msg;
+{
+ int c, pri, flags;
+ char *lp, *p, *q, line[MAXLINE + 1];
+
+ (void)strcpy(line, "kernel: ");
+ 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.
+ */
+void
+logmsg(pri, msg, from, flags)
+ int pri;
+ char *msg, *from;
+ int flags;
+{
+ struct filed *f;
+ int fac, msglen, omask, prilev;
+ char *timestamp;
+
+ 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;
+ (void)strncpy(f->f_lasttime, timestamp, 15);
+ (void)strncpy(f->f_prevhost, from,
+ sizeof(f->f_prevhost));
+ if (msglen < MAXSVLINE) {
+ f->f_prevlen = msglen;
+ f->f_prevpri = pri;
+ (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);
+}
+
+void
+fprintlog(f, flags, msg)
+ struct filed *f;
+ int flags;
+ char *msg;
+{
+ struct iovec iov[6];
+ struct iovec *v;
+ 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.
+ */
+void
+wallmsg(f, iov)
+ struct filed *f;
+ struct iovec *iov;
+{
+ static int reenter; /* avoid calling ourselves */
+ FILE *uf;
+ struct utmp ut;
+ int i;
+ char *p;
+ char line[sizeof(ut.ut_line) + 1];
+
+ 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;
+ strncpy(line, ut.ut_line, sizeof(ut.ut_line));
+ line[sizeof(ut.ut_line)] = '\0';
+ if (f->f_type == F_WALL) {
+ if ((p = ttymsg(iov, 6, line, 60*5)) != NULL) {
+ 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, line, 60*5)) != NULL) {
+ errno = 0; /* already in msg */
+ logerror(p);
+ }
+ break;
+ }
+ }
+ }
+ (void)fclose(uf);
+ reenter = 0;
+}
+
+void
+reapchild(signo)
+ int signo;
+{
+ 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;
+ char *p;
+
+ 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 = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0)
+ *p = '\0';
+ return (hp->h_name);
+}
+
+void
+domark(signo)
+ int signo;
+{
+ struct filed *f;
+
+ 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.
+ */
+void
+logerror(type)
+ char *type;
+{
+ char buf[100];
+
+ if (errno)
+ (void)snprintf(buf,
+ sizeof(buf), "syslogd: %s: %s", type, strerror(errno));
+ else
+ (void)snprintf(buf, sizeof(buf), "syslogd: %s", type);
+ errno = 0;
+ dprintf("%s\n", buf);
+ logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE);
+}
+
+void
+die(signo)
+ int signo;
+{
+ 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 (signo) {
+ dprintf("syslogd: exiting on signal %d\n", signo);
+ (void)sprintf(buf, "exiting on signal %d", signo);
+ errno = 0;
+ logerror(buf);
+ }
+ (void)unlink(LogName);
+ exit(0);
+}
+
+/*
+ * INIT -- Initialize syslogd from configuration table
+ */
+void
+init(signo)
+ int signo;
+{
+ int i;
+ FILE *cf;
+ struct filed *f, *next, **nextp;
+ char *p;
+ char cline[LINE_MAX];
+
+ 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)
+ continue;
+ if (*p == NULL || *p == '#')
+ continue;
+ for (p = strchr(cline, '\0'); isspace(*--p);)
+ continue;
+ *++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
+ */
+void
+cfline(line, f)
+ char *line;
+ struct filed *f;
+{
+ struct hostent *hp;
+ int i, pri;
+ char *bp, *p, *q;
+ char buf[MAXLINE], ebuf[100];
+
+ dprintf("cfline(%s)\n", line);
+
+ errno = 0; /* keep strerror() stuff out of logerror messages */
+
+ /* clear out file entry */
+ memset(f, 0, 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 && !strchr("\t,;", *q); )
+ *bp++ = *q++;
+ *bp = '\0';
+
+ /* skip cruft */
+ while (strchr(", ;", *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 && !strchr("\t.;", *p)) {
+ for (bp = buf; *p && !strchr("\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;
+ }
+ memset(&f->f_un.f_forw.f_addr, 0,
+ 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;
+ memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_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
+ */
+int
+decode(name, codetab)
+ const char *name;
+ CODE *codetab;
+{
+ CODE *c;
+ char *p, buf[40];
+
+ if (isdigit(*name))
+ return (atoi(name));
+
+ for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) {
+ if (isupper(*name))
+ *p = tolower(*name);
+ else
+ *p = *name;
+ }
+ *p = '\0';
+ 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/Makefile b/usr.sbin/tcpdump/Makefile
new file mode 100644
index 0000000..0a1f253
--- /dev/null
+++ b/usr.sbin/tcpdump/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 0.1 (RGrimes) 4/4/93
+
+SUBDIR= tcpdump tcpslice
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/tcpdump/Makefile.inc b/usr.sbin/tcpdump/Makefile.inc
new file mode 100644
index 0000000..26c6f1c
--- /dev/null
+++ b/usr.sbin/tcpdump/Makefile.inc
@@ -0,0 +1,3 @@
+# @(#)Makefile.inc 5.1 (Berkeley) 5/11/90
+
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/tcpdump/tcpdump/Makefile b/usr.sbin/tcpdump/tcpdump/Makefile
new file mode 100644
index 0000000..d9ec9a1
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/Makefile
@@ -0,0 +1,26 @@
+# @(#)Makefile 0.1 (RWGrimes) 3/24/93
+
+PROG= tcpdump
+CFLAGS+=-DCSLIP -DPPP -I. -I${.CURDIR}/../../mrouted
+MAN1= tcpdump.1
+SRCS= version.c addrtoname.c bpf_dump.c bpf_filter.c bpf_image.c etherent.c \
+ gencode.c inet.c md.c nametoaddr.c optimize.c os.c pcap.c \
+ print-arp.c print-atalk.c print-bootp.c print-domain.c \
+ print-egp.c print-ether.c print-fddi.c print-icmp.c print-ip.c \
+ print-nfs.c print-ntp.c print-null.c print-ospf.c print-ppp.c \
+ print-rip.c print-sl.c print-snmp.c print-sunrpc.c print-tcp.c \
+ print-tftp.c print-udp.c savefile.c tcpdump.c tcpgram.c \
+ tcplex.c util.c
+.PATH: /sys/net
+CLEANFILES+= tcpgram.c tcplex.c y.tab.h y.tab.c version.c version.h
+DPADD+= ${LIBL}
+LDADD+= -ll
+
+version.c version.h: VERSION
+ rm -f version.c ; \
+ sed 's/.*/char version[] = "&";/' $(.CURDIR)/VERSION > version.c
+ set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/VERSION` ; \
+ { echo '#define VERSION_MAJOR' $$1 ; \
+ echo '#define VERSION_MINOR' $$2 ; } > version.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/tcpdump/tcpdump/VERSION b/usr.sbin/tcpdump/tcpdump/VERSION
new file mode 100644
index 0000000..c043eea
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/VERSION
@@ -0,0 +1 @@
+2.2.1
diff --git a/usr.sbin/tcpdump/tcpdump/addrtoname.c b/usr.sbin/tcpdump/tcpdump/addrtoname.c
new file mode 100644
index 0000000..5c70865
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/addrtoname.c
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ *
+ * Internet, ethernet, port, and protocol string to address
+ * and address to string conversion routines
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: addrtoname.c,v 1.14 92/05/25 14:29:07 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <strings.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <signal.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "nametoaddr.h"
+#include "etherent.h"
+
+/*
+ * hash tables for whatever-to-name translations
+ */
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+ u_long addr;
+ char *name;
+ struct hnamemem *nxt;
+};
+
+struct hnamemem hnametable[HASHNAMESIZE];
+struct hnamemem tporttable[HASHNAMESIZE];
+struct hnamemem uporttable[HASHNAMESIZE];
+struct hnamemem eprototable[HASHNAMESIZE];
+
+struct enamemem {
+ u_short e_addr0;
+ u_short e_addr1;
+ u_short e_addr2;
+ char *e_name;
+ struct enamemem *e_nxt;
+};
+
+struct enamemem enametable[HASHNAMESIZE];
+
+
+/*
+ * A faster replacement for inet_ntoa().
+ */
+char *
+intoa(addr)
+ u_long 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_long f_netmask;
+static u_long f_localnet;
+static u_long 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 void
+nohostname()
+{
+ 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(ap)
+ u_char *ap;
+{
+ register struct hnamemem *p;
+ register struct hostent *hp;
+ register char *cp;
+ u_long addr;
+
+#ifndef TCPDUMP_ALIGN
+ addr = *(u_long *)ap;
+#else
+ /*
+ * Deal with alignment.
+ */
+ switch ((int)ap & 3) {
+
+ case 0:
+ addr = *(u_long *)ap;
+ break;
+
+ case 2:
+#if BYTE_ORDER == LITTLE_ENDIAN
+ addr = ((u_long)*(u_short *)(ap + 2) << 16) |
+ (u_long)*(u_short *)ap;
+#else
+ addr = ((u_long)*(u_short *)ap << 16) |
+ (u_long)*(u_short *)(ap + 2);
+#endif
+ break;
+
+ default:
+#if BYTE_ORDER == LITTLE_ENDIAN
+ addr = ((u_long)ap[0] << 24) |
+ ((u_long)ap[1] << 16) |
+ ((u_long)ap[2] << 8) |
+ (u_long)ap[3];
+#else
+ addr = ((u_long)ap[3] << 24) |
+ ((u_long)ap[2] << 16) |
+ ((u_long)ap[1] << 8) |
+ (u_long)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 *index();
+ char *dotp;
+ u_int len = strlen(hp->h_name) + 1;
+ p->name = (char *)malloc(len);
+ (void)strcpy(p->name, hp->h_name);
+ if (Nflag) {
+ /* Remove domain qualifications */
+ dotp = index(p->name, '.');
+ if (dotp)
+ *dotp = 0;
+ }
+ return (p->name);
+ }
+ }
+ }
+ cp = intoa(addr);
+ p->name = (char *)malloc((unsigned)(strlen(cp) + 1));
+ (void)strcpy(p->name, cp);
+ return (p->name);
+}
+
+static char hex[] = "0123456789abcdef";
+
+
+/* Find the hash node that corresponds the ether address 'ep'. */
+
+static inline struct enamemem *
+lookup_emem(ep)
+ 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;
+}
+
+char *
+etheraddr_string(ep)
+ register 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) {
+ cp = ETHER_ntohost(ep);
+ if (cp) {
+ tp->e_name = cp;
+ return cp;
+ }
+ }
+#endif
+ tp->e_name = cp = (char *)malloc(sizeof("00:00:00:00:00:00"));
+
+ if (j = *ep >> 4)
+ *cp++ = hex[j];
+ *cp++ = hex[*ep++ & 0xf];
+ for (i = 5; (int)--i >= 0;) {
+ *cp++ = ':';
+ if (j = *ep >> 4)
+ *cp++ = hex[j];
+ *cp++ = hex[*ep++ & 0xf];
+ }
+ *cp = '\0';
+ return (tp->e_name);
+}
+
+char *
+etherproto_string(port)
+ 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 *
+tcpport_string(port)
+ u_short port;
+{
+ register struct hnamemem *tp;
+ register int 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(port)
+ register u_short port;
+{
+ register struct hnamemem *tp;
+ register int 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()
+{
+ struct servent *sv;
+ register struct hnamemem *table;
+ register int i;
+
+ while (sv = getservent()) {
+ NTOHS(sv->s_port);
+ i = sv->s_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", sv->s_port);
+ table->name = (char *)malloc((unsigned)strlen(buf)+1);
+ (void)strcpy(table->name, buf);
+ } else {
+ table->name =
+ (char *)malloc((unsigned)strlen(sv->s_name)+1);
+ (void)strcpy(table->name, sv->s_name);
+ }
+ table->addr = sv->s_port;
+ table->nxt = (struct hnamemem *)calloc(1, sizeof(*table));
+ }
+ endservent();
+}
+
+#include "etherproto.h"
+
+/* Static data base of ether protocol types. */
+struct eproto eproto_db[] = {
+ { "pup", ETHERTYPE_PUP },
+ { "xns", ETHERTYPE_NS },
+ { "ip", ETHERTYPE_IP },
+ { "arp", ETHERTYPE_ARP },
+ { "rarp", ETHERTYPE_REVARP },
+ { "sprite", ETHERTYPE_SPRITE },
+ { "mopdl", ETHERTYPE_MOPDL },
+ { "moprc", ETHERTYPE_MOPRC },
+ { "decnet", ETHERTYPE_DN },
+ { "lat", ETHERTYPE_LAT },
+ { "lanbridge", ETHERTYPE_LANBRIDGE },
+ { "vexp", ETHERTYPE_VEXP },
+ { "vprod", ETHERTYPE_VPROD },
+ { "atalk", ETHERTYPE_ATALK },
+ { "atalkarp", ETHERTYPE_AARP },
+ { "loopback", ETHERTYPE_LOOPBACK },
+ { (char *)0, 0 }
+};
+
+static void
+init_eprotoarray()
+{
+ 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));
+ }
+}
+
+static void
+init_etherarray()
+{
+#ifndef ETHER_SERVICE
+ FILE *fp;
+ struct etherent *ep;
+ struct enamemem *tp;
+
+ fp = fopen(ETHERS_FILE, "r");
+ if (fp == 0)
+ /* No data base; will have to settle for
+ numeric addresses. */
+ return;
+
+ while (ep = next_etherent(fp)) {
+ tp = lookup_emem(ep->addr);
+ tp->e_name = (char *)malloc((unsigned)strlen(ep->name)+1);
+ strcpy(tp->e_name, ep->name);
+ }
+#endif
+}
+
+/*
+ * 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(fflag, localnet, mask)
+ int fflag;
+ u_long localnet;
+ u_long 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();
+}
diff --git a/usr.sbin/tcpdump/tcpdump/addrtoname.h b/usr.sbin/tcpdump/tcpdump/addrtoname.h
new file mode 100644
index 0000000..6dc6979
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/addrtoname.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: addrtoname.h,v 1.5 92/03/17 13:41:37 mccanne Exp $ (LBL)
+ */
+
+/* Name to address translation routines. */
+
+extern char *etheraddr_string();
+extern char *etherproto_string();
+extern char *tcpport_string();
+extern char *udpport_string();
+extern char *getname();
+extern char *intoa();
+
+extern void init_addrtoname();
+extern void no_foreign_names();
+
+#define ipaddr_string(p) getname((u_char *)(p))
diff --git a/usr.sbin/tcpdump/tcpdump/appletalk.h b/usr.sbin/tcpdump/tcpdump/appletalk.h
new file mode 100644
index 0000000..90c8c80
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/appletalk.h
@@ -0,0 +1,156 @@
+/*
+ * 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: (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.6 90/10/03 22:14:26 leres Exp $ (LBL)
+ */
+
+/* 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;
+ long 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;
+
+
+/* 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/tcpdump/bootp.h b/usr.sbin/tcpdump/tcpdump/bootp.h
new file mode 100644
index 0000000..ab474cf
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/bootp.h
@@ -0,0 +1,103 @@
+/* @(#) $Header: bootp.h,v 1.2 90/05/29 21:29:16 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 */
+ unsigned long 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)
+
+
+
+/*
+ * "vendor" data permitted for CMU bootp clients.
+ */
+
+struct cmu_vend {
+ unsigned char v_magic[4]; /* magic number */
+ unsigned long 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[25]; /* currently unused */
+};
+
+
+/* v_flags values */
+#define VF_SMASK 1 /* Subnet mask field contains valid data */
diff --git a/usr.sbin/tcpdump/tcpdump/bpf_dump.c b/usr.sbin/tcpdump/tcpdump/bpf_dump.c
new file mode 100644
index 0000000..fab9596
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/bpf_dump.c
@@ -0,0 +1,61 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#) $Header: bpf_dump.c,v 1.1 92/01/29 13:25:30 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+void
+bpf_dump(p, option)
+ 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/tcpdump/bpf_image.c b/usr.sbin/tcpdump/tcpdump/bpf_image.c
new file mode 100644
index 0000000..d36eab2
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/bpf_image.c
@@ -0,0 +1,282 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: bpf_image.c,v 1.10 92/01/26 21:01:16 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+char *
+bpf_image(p, n)
+ struct bpf_insn *p;
+ int n;
+{
+ int v;
+ char *fmt, *op;
+ static char image[256];
+ char operand[64];
+
+ v = p->k;
+ switch (p->code) {
+
+ default:
+ op = "unimp";
+ fmt = "0x%x";
+ v = p->code;
+ break;
+
+ case BPF_RET|BPF_K:
+ op = "ret";
+ fmt = "#%d";
+ break;
+
+ case BPF_RET|BPF_A:
+ op = "ret";
+ fmt = "";
+ break;
+
+ case BPF_LD|BPF_W|BPF_ABS:
+ op = "ld";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_H|BPF_ABS:
+ op = "ldh";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_B|BPF_ABS:
+ op = "ldb";
+ fmt = "[%d]";
+ break;
+
+ case BPF_LD|BPF_W|BPF_LEN:
+ op = "ld";
+ fmt = "#pktlen";
+ break;
+
+ case BPF_LD|BPF_W|BPF_IND:
+ op = "ld";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_H|BPF_IND:
+ op = "ldh";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_B|BPF_IND:
+ op = "ldb";
+ fmt = "[x + %d]";
+ break;
+
+ case BPF_LD|BPF_IMM:
+ op = "ld";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ op = "ldx";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ op = "ldxb";
+ fmt = "4*([%d]&0xf)";
+ break;
+
+ case BPF_LD|BPF_MEM:
+ op = "ld";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ op = "ldx";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_ST:
+ op = "st";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_STX:
+ op = "stx";
+ fmt = "M[%d]";
+ break;
+
+ case BPF_JMP|BPF_JA:
+ op = "ja";
+ fmt = "%d";
+ v = n + p->k;
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_K:
+ op = "jgt";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_K:
+ op = "jge";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_K:
+ op = "jeq";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_K:
+ op = "jset";
+ fmt = "#0x%x";
+ break;
+
+ case BPF_JMP|BPF_JGT|BPF_X:
+ op = "jgt";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JGE|BPF_X:
+ op = "jge";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JEQ|BPF_X:
+ op = "jeq";
+ fmt = "x";
+ break;
+
+ case BPF_JMP|BPF_JSET|BPF_X:
+ op = "jset";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ op = "add";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_X:
+ op = "sub";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_X:
+ op = "mul";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_X:
+ op = "div";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_X:
+ op = "and";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_X:
+ op = "or";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_X:
+ op = "lsh";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = "rsh";
+ fmt = "x";
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ op = "add";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_SUB|BPF_K:
+ op = "sub";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_MUL|BPF_K:
+ op = "mul";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_DIV|BPF_K:
+ op = "div";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_AND|BPF_K:
+ op = "and";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_OR|BPF_K:
+ op = "or";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_LSH|BPF_K:
+ op = "lsh";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = "rsh";
+ fmt = "#%d";
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ op = "neg";
+ fmt = "";
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ op = "tax";
+ fmt = "";
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ op = "txa";
+ fmt = "";
+ break;
+ }
+ (void)sprintf(operand, fmt, v);
+ (void)sprintf(image,
+ (BPF_CLASS(p->code) == BPF_JMP &&
+ BPF_OP(p->code) != BPF_JA) ?
+ "(%03d) %-8s %-16s jt %d\tjf %d"
+ : "(%03d) %-8s %s",
+ n, op, operand, n + 1 + p->jt, n + 1 + p->jf);
+ return image;
+}
diff --git a/usr.sbin/tcpdump/tcpdump/etherent.c b/usr.sbin/tcpdump/tcpdump/etherent.c
new file mode 100644
index 0000000..9d7ee80
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/etherent.c
@@ -0,0 +1,144 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#) $Header: etherent.c,v 1.2 90/09/20 23:16:06 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "interface.h"
+
+#ifndef ETHER_SERVICE
+
+#include "etherent.h"
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+static inline int
+skip_space(f)
+ FILE *f;
+{
+ int c;
+
+ do {
+ c = getc(f);
+ } while (isspace(c) && c != '\n');
+
+ return c;
+}
+
+static inline int
+skip_line(f)
+ FILE *f;
+{
+ int c;
+
+ do
+ c = getc(f);
+ while (c != '\n' && c != EOF);
+
+ return c;
+}
+
+struct etherent *
+next_etherent(fp)
+ FILE *fp;
+{
+ register int c, d, i;
+ char *bp;
+ static struct etherent e;
+ static int nline = 1;
+ top:
+ while (nline) {
+ /* Find addr */
+ c = skip_space(fp);
+ if (c == '\n')
+ continue;
+ /* If this is a comment, or first thing on line
+ cannot be etehrnet address, skip the line. */
+ else if (!isxdigit(c))
+ c = skip_line(fp);
+ else {
+ /* must be the start of an address */
+ for (i = 0; i < 6; i += 1) {
+ d = xdtoi(c);
+ c = getc(fp);
+ if (c != ':') {
+ d <<= 4;
+ d |= xdtoi(c);
+ c = getc(fp);
+ }
+ e.addr[i] = d;
+ if (c != ':')
+ break;
+ c = getc(fp);
+ }
+ nline = 0;
+ }
+ if (c == EOF)
+ return 0;
+ }
+
+ /* If we started a new line, 'c' holds the char past the ether addr,
+ which we assume is white space. If we are continuning a line,
+ 'c' is garbage. In either case, we can throw it away. */
+
+ c = skip_space(fp);
+ if (c == '\n') {
+ nline = 1;
+ goto top;
+ }
+ else if (c == '#') {
+ (void)skip_line(fp);
+ nline = 1;
+ goto top;
+ }
+ else if (c == EOF)
+ return 0;
+
+ /* Must be a name. */
+ bp = e.name;
+ /* Use 'd' to prevent buffer overflow. */
+ d = sizeof(e.name) - 1;
+ do {
+ *bp++ = c;
+ c = getc(fp);
+ } while (!isspace(c) && c != EOF && --d > 0);
+ *bp = '\0';
+ if (c == '\n')
+ nline = 1;
+
+ return &e;
+}
+
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/etherent.h b/usr.sbin/tcpdump/tcpdump/etherent.h
new file mode 100644
index 0000000..83ebaab
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/etherent.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: etherent.h,v 1.2 90/09/20 23:16:17 mccanne Exp $ (LBL)
+ */
+
+/* File name of ethernet address data base. */
+
+#define ETHERS_FILE "/etc/ethers"
+
+struct etherent {
+ u_char addr[6];
+ char name[122];
+};
+
+struct etherent *next_etherent();
+
diff --git a/usr.sbin/tcpdump/tcpdump/etherproto.h b/usr.sbin/tcpdump/tcpdump/etherproto.h
new file mode 100644
index 0000000..5c0e245
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/etherproto.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: etherproto.h,v 1.7 90/10/10 15:04:04 mccanne 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_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 /* XXX */
+#endif
+#ifndef ETHERTYPE_AARP
+#define ETHERTYPE_AARP 0x80f3
+#endif
+#ifndef ETHERTYPE_NS
+#define ETHERTYPE_NS 0x0600
+#endif
+
+struct eproto {
+ char *s;
+ u_short p;
+};
+
+extern struct eproto eproto_db[];
diff --git a/usr.sbin/tcpdump/tcpdump/extract.h b/usr.sbin/tcpdump/tcpdump/extract.h
new file mode 100644
index 0000000..bd45c59
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/extract.h
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: extract.h,v 1.4 92/05/25 14:28:36 mccanne 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_long)*((u_char *)p+3)<<24|\
+ (u_long)*((u_char *)p+2)<<16|\
+ (u_long)*((u_char *)p+1)<<8|\
+ (u_long)*((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_long)*((u_char *)p+0)<<24|\
+ (u_long)*((u_char *)p+1)<<16|\
+ (u_long)*((u_char *)p+2)<<8|\
+ (u_long)*((u_char *)p+3)<<0)
+#endif
+#else
+#define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
+#define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/gencode.c b/usr.sbin/tcpdump/tcpdump/gencode.c
new file mode 100644
index 0000000..8cb48ea
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/gencode.c
@@ -0,0 +1,1384 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#) $Header: gencode.c,v 1.33 92/05/22 16:38:39 mccanne Exp $ (LBL)";
+#endif
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "gencode.h"
+#include "nametoaddr.h"
+#include "extract.h"
+
+#define JMP(c) ((c)|BPF_JMP|BPF_K)
+
+extern struct bpf_insn *icode_to_fcode();
+extern u_long net_mask();
+static void init_linktype();
+
+static int alloc_reg();
+static void free_reg();
+
+static struct block *root;
+
+/*
+ * We divy out chunks of memory rather than call malloc each time so
+ * we don't have to worry about leaking memory. It's probably
+ * not a big deal if all this memory was wasted but it this ever
+ * goes into a library that would probably not be a good idea.
+ */
+#define NCHUNKS 16
+#define CHUNK0SIZE 1024
+struct chunk {
+ u_int n_left;
+ void *m;
+};
+
+static struct chunk chunks[NCHUNKS];
+static int cur_chunk;
+
+static void *
+newchunk(n)
+ u_int n;
+{
+ struct chunk *cp;
+ int k, size;
+
+ /* XXX Round up to nearest long. */
+ n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1);
+
+ cp = &chunks[cur_chunk];
+ if (n > cp->n_left) {
+ ++cp, k = ++cur_chunk;
+ if (k >= NCHUNKS)
+ error("out of memory");
+ size = CHUNK0SIZE << k;
+ cp->m = (void *)malloc(size);
+ bzero((char *)cp->m, size);
+ cp->n_left = size;
+ if (n > size)
+ error("out of memory");
+ }
+ cp->n_left -= n;
+ return (void *)((char *)cp->m + cp->n_left);
+}
+
+static void
+freechunks()
+{
+ int i;
+
+ for (i = 0; i < NCHUNKS; ++i)
+ if (chunks[i].m)
+ free(chunks[i].m);
+}
+
+static inline struct block *
+new_block(code)
+ int code;
+{
+ struct block *p;
+
+ p = (struct block *)newchunk(sizeof(*p));
+ p->s.code = code;
+ p->head = p;
+
+ return p;
+}
+
+static inline struct slist *
+new_stmt(code)
+ int code;
+{
+ struct slist *p;
+
+ p = (struct slist *)newchunk(sizeof(*p));
+ p->s.code = code;
+
+ return p;
+}
+
+static struct block *
+gen_retblk(v)
+ int v;
+{
+ struct block *b = new_block(BPF_RET|BPF_K);
+
+ b->s.k = v;
+ return b;
+}
+
+static inline void
+syntax()
+{
+ error("syntax error in filter expression");
+}
+
+static u_long netmask;
+
+struct bpf_program *
+parse(buf, Oflag, linktype, mask)
+ char *buf;
+ int Oflag;
+ int linktype;
+ u_long mask;
+{
+ extern int n_errors;
+ static struct bpf_program F;
+ struct bpf_insn *p;
+ int len;
+
+ netmask = mask;
+
+ F.bf_insns = 0;
+ F.bf_len = 0;
+
+ lex_init(buf ? buf : "");
+ init_linktype(linktype);
+ yyparse();
+
+ if (n_errors)
+ syntax();
+
+ if (root == 0)
+ root = gen_retblk(snaplen);
+
+ if (Oflag) {
+ optimize(&root);
+ if (root == 0 ||
+ (root->s.code == (BPF_RET|BPF_K) && root->s.k == 0))
+ error("expression rejects all packets");
+ }
+ p = icode_to_fcode(root, &len);
+ F.bf_insns = p;
+ F.bf_len = len;
+
+ freechunks();
+ return &F;
+}
+
+/*
+ * Backpatch the blocks in 'list' to 'target'. The 'sense' field indicates
+ * which of the jt and jf fields has been resolved and which is a pointer
+ * back to another unresolved block (or nil). At least one of the fields
+ * in each block is already resolved.
+ */
+static void
+backpatch(list, target)
+ struct block *list, *target;
+{
+ struct block *next;
+
+ while (list) {
+ if (!list->sense) {
+ next = JT(list);
+ JT(list) = target;
+ } else {
+ next = JF(list);
+ JF(list) = target;
+ }
+ list = next;
+ }
+}
+
+/*
+ * Merge the lists in b0 and b1, using the 'sense' field to indicate
+ * which of jt and jf is the link.
+ */
+static void
+merge(b0, b1)
+ struct block *b0, *b1;
+{
+ register struct block **p = &b0;
+
+ /* Find end of list. */
+ while (*p)
+ p = !((*p)->sense) ? &JT(*p) : &JF(*p);
+
+ /* Concatenate the lists. */
+ *p = b1;
+}
+
+void
+finish_parse(p)
+ struct block *p;
+{
+ backpatch(p, gen_retblk(snaplen));
+ p->sense = !p->sense;
+ backpatch(p, gen_retblk(0));
+ root = p->head;
+}
+
+void
+gen_and(b0, b1)
+ struct block *b0, *b1;
+{
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ b1->sense = !b1->sense;
+ merge(b1, b0);
+ b1->sense = !b1->sense;
+ b1->head = b0->head;
+}
+
+void
+gen_or(b0, b1)
+ struct block *b0, *b1;
+{
+ b0->sense = !b0->sense;
+ backpatch(b0, b1->head);
+ b0->sense = !b0->sense;
+ merge(b1, b0);
+ b1->head = b0->head;
+}
+
+void
+gen_not(b)
+ struct block *b;
+{
+ b->sense = !b->sense;
+}
+
+static struct block *
+gen_cmp(offset, size, v)
+ u_int offset, size;
+ long v;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LD|BPF_ABS|size);
+ s->s.k = offset;
+
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ b->s.k = v;
+
+ return b;
+}
+
+struct block *
+gen_mcmp(offset, size, v, mask)
+ u_int offset, size;
+ long v;
+ u_long mask;
+{
+ struct block *b = gen_cmp(offset, size, v);
+ struct slist *s;
+
+ if (mask != 0xffffffff) {
+ s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ s->s.k = mask;
+ b->stmts->next = s;
+ }
+ return b;
+}
+
+struct block *
+gen_bcmp(offset, size, v)
+ u_int offset;
+ u_int size;
+ u_char *v;
+{
+ struct block *b, *tmp;
+ int k;
+
+ b = 0;
+ while (size >= 4) {
+ k = size - 4;
+ tmp = gen_cmp(offset + k, BPF_W, EXTRACT_LONG(&v[k]));
+ if (b != 0)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 4;
+ }
+ while (size >= 2) {
+ k = size - 2;
+ tmp = gen_cmp(offset + k, BPF_H, (long)EXTRACT_SHORT(&v[k]));
+ if (b != 0)
+ gen_and(b, tmp);
+ b = tmp;
+ size -= 2;
+ }
+ if (size > 0) {
+ tmp = gen_cmp(offset, BPF_B, (long)v[0]);
+ if (b != 0)
+ gen_and(b, tmp);
+ b = tmp;
+ }
+ return b;
+}
+
+/*
+ * Various code contructs need to know the layout of the data link
+ * layer. These variables give the necessary offsets. off_linktype
+ * is set to -1 for no encapsulation, in which case, IP is assumed.
+ */
+static u_int off_linktype;
+static u_int off_nl;
+static int linktype;
+
+static void
+init_linktype(type)
+ int type;
+{
+ linktype = type;
+
+ switch (type) {
+
+ case DLT_EN10MB:
+ off_linktype = 12;
+ off_nl = 14;
+ return;
+
+ case DLT_SLIP:
+ /*
+ * SLIP doesn't have a link level type. The 16 byte
+ * header is hacked into our SLIP driver.
+ */
+ off_linktype = -1;
+ off_nl = 16;
+ return;
+
+ case DLT_NULL:
+ off_linktype = -1;
+ off_nl = 0;
+ return;
+
+ case DLT_PPP:
+ off_linktype = 2;
+ off_nl = 4;
+ return;
+
+ case DLT_FDDI:
+ off_linktype = 19;
+ off_nl = 21;
+ return;
+
+ case DLT_IEEE802:
+ off_linktype = 20;
+ off_nl = 22;
+ return;
+ }
+ error("unknown data link type 0x%x", linktype);
+ /* NOTREACHED */
+}
+
+static struct block *
+gen_uncond(rsense)
+ int rsense;
+{
+ struct block *b;
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_IMM);
+ s->s.k = !rsense;
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+
+ return b;
+}
+
+static inline struct block *
+gen_true()
+{
+ return gen_uncond(1);
+}
+
+static inline struct block *
+gen_false()
+{
+ return gen_uncond(0);
+}
+
+struct block *
+gen_linktype(proto)
+ int proto;
+{
+ switch (linktype) {
+ case DLT_SLIP:
+ if (proto == ETHERTYPE_IP)
+ return gen_true();
+ else
+ return gen_false();
+
+ case DLT_PPP:
+ if (proto == ETHERTYPE_IP)
+ proto = 0x0021; /* XXX - need ppp.h defs */
+ break;
+ }
+ return gen_cmp(off_linktype, BPF_H, (long)proto);
+}
+
+static struct block *
+gen_hostop(addr, mask, dir, proto, src_off, dst_off)
+ u_long addr;
+ u_long mask;
+ int dir, proto;
+ u_int src_off, dst_off;
+{
+ struct block *b0, *b1;
+ u_int offset;
+
+ switch (dir) {
+
+ case Q_SRC:
+ offset = src_off;
+ break;
+
+ case Q_DST:
+ offset = dst_off;
+ break;
+
+ case Q_AND:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ b0 = gen_hostop(addr, mask, Q_SRC, proto, src_off, dst_off);
+ b1 = gen_hostop(addr, mask, Q_DST, proto, src_off, dst_off);
+ gen_or(b0, b1);
+ return b1;
+
+ default:
+ abort();
+ }
+ b0 = gen_linktype(proto);
+ b1 = gen_mcmp(offset, BPF_W, (long)addr, mask);
+ gen_and(b0, b1);
+ return b1;
+}
+
+static struct block *
+gen_ehostop(eaddr, dir)
+ u_char *eaddr;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ switch (dir) {
+ case Q_SRC:
+ return gen_bcmp(6, 6, eaddr);
+
+ case Q_DST:
+ return gen_bcmp(0, 6, eaddr);
+
+ case Q_AND:
+ b0 = gen_ehostop(eaddr, Q_SRC);
+ b1 = gen_ehostop(eaddr, Q_DST);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_DEFAULT:
+ case Q_OR:
+ b0 = gen_ehostop(eaddr, Q_SRC);
+ b1 = gen_ehostop(eaddr, Q_DST);
+ gen_or(b0, b1);
+ return b1;
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+static struct block *
+gen_host(addr, mask, proto, dir)
+ u_long addr;
+ u_long mask;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ b0 = gen_host(addr, mask, Q_IP, dir);
+ b1 = gen_host(addr, mask, Q_ARP, dir);
+ gen_or(b0, b1);
+ b0 = gen_host(addr, mask, Q_RARP, dir);
+ gen_or(b1, b0);
+ return b0;
+
+ case Q_IP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_IP,
+ off_nl + 12, off_nl + 16);
+
+ case Q_RARP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_REVARP,
+ off_nl + 14, off_nl + 24);
+
+ case Q_ARP:
+ return gen_hostop(addr, mask, dir, ETHERTYPE_ARP,
+ off_nl + 14, off_nl + 24);
+
+ case Q_TCP:
+ error("'tcp' modifier applied to host");
+
+ case Q_UDP:
+ error("'udp' modifier applied to host");
+
+ case Q_ICMP:
+ error("'icmp' modifier applied to host");
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+static struct block *
+gen_gateway(eaddr, alist, proto, dir)
+ u_char *eaddr;
+ u_long **alist;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ if (dir != 0)
+ error("direction applied to 'gateway'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ b0 = gen_ehostop(eaddr, Q_OR);
+ b1 = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+ while (*alist) {
+ tmp = gen_host(**alist++, 0xffffffffL, proto, Q_OR);
+ gen_or(b1, tmp);
+ b1 = tmp;
+ }
+ gen_not(b1);
+ gen_and(b0, b1);
+ return b1;
+ }
+ error("illegal modifier of 'gateway'");
+ /* NOTREACHED */
+}
+
+struct block *
+gen_proto_abbrev(proto)
+ int proto;
+{
+ struct block *b0, *b1;
+
+ switch (proto) {
+
+ case Q_TCP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_TCP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_UDP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_UDP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_ICMP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)IPPROTO_ICMP);
+ gen_and(b0, b1);
+ break;
+
+ case Q_IP:
+ b1 = gen_linktype(ETHERTYPE_IP);
+ break;
+
+ case Q_ARP:
+ b1 = gen_linktype(ETHERTYPE_ARP);
+ break;
+
+ case Q_RARP:
+ b1 = gen_linktype(ETHERTYPE_REVARP);
+ break;
+
+ case Q_LINK:
+ error("link layer applied in wrong context");
+
+ default:
+ abort();
+ }
+ return b1;
+}
+
+static struct block *
+gen_ipfrag()
+{
+ struct slist *s;
+ struct block *b;
+
+ /* not ip frag */
+ s = new_stmt(BPF_LD|BPF_H|BPF_ABS);
+ s->s.k = off_nl + 6;
+ b = new_block(JMP(BPF_JSET));
+ b->s.k = 0x1fff;
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+static struct block *
+gen_portatom(off, v)
+ int off;
+ long v;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s->s.k = off_nl;
+
+ s->next = new_stmt(BPF_LD|BPF_IND|BPF_H);
+ s->next->s.k = off_nl + off;
+
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ b->s.k = v;
+
+ return b;
+}
+
+struct block *
+gen_portop(port, proto, dir)
+ int port;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ip proto 'proto' */
+ tmp = gen_cmp(off_nl + 9, BPF_B, (long)proto);
+ b0 = gen_ipfrag();
+ gen_and(tmp, b0);
+
+ switch (dir) {
+ case Q_SRC:
+ b1 = gen_portatom(0, (long)port);
+ break;
+
+ case Q_DST:
+ b1 = gen_portatom(2, (long)port);
+ break;
+
+ case Q_OR:
+ case Q_DEFAULT:
+ tmp = gen_portatom(0, (long)port);
+ b1 = gen_portatom(2, (long)port);
+ gen_or(tmp, b1);
+ break;
+
+ case Q_AND:
+ tmp = gen_portatom(0, (long)port);
+ b1 = gen_portatom(2, (long)port);
+ gen_and(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+
+ return b1;
+}
+
+static struct block *
+gen_port(port, ip_proto, dir)
+ int port;
+ int ip_proto;
+ int dir;
+{
+ struct block *b0, *b1, *tmp;
+
+ /* ether proto ip */
+ b0 = gen_linktype(ETHERTYPE_IP);
+
+ switch (ip_proto) {
+ case IPPROTO_UDP:
+ case IPPROTO_TCP:
+ b1 = gen_portop(port, ip_proto, dir);
+ break;
+
+ case PROTO_UNDEF:
+ tmp = gen_portop(port, IPPROTO_TCP, dir);
+ b1 = gen_portop(port, IPPROTO_UDP, dir);
+ gen_or(tmp, b1);
+ break;
+
+ default:
+ abort();
+ }
+ gen_and(b0, b1);
+ return b1;
+}
+
+int
+lookup_proto(name, proto)
+ char *name;
+ int proto;
+{
+ int v;
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ v = s_nametoproto(name);
+ if (v == PROTO_UNDEF)
+ error("unknown ip proto '%s'", name);
+ break;
+
+ case Q_LINK:
+ /* XXX should look up h/w protocol type based on linktype */
+ v = s_nametoeproto(name);
+ if (v == PROTO_UNDEF)
+ error("unknown ether proto '%s'", name);
+ break;
+
+ default:
+ v = PROTO_UNDEF;
+ break;
+ }
+ return v;
+}
+
+struct block *
+gen_proto(v, proto, dir)
+ int v;
+ int proto;
+ int dir;
+{
+ struct block *b0, *b1;
+
+ if (dir != Q_DEFAULT)
+ error("direction applied to 'proto'");
+
+ switch (proto) {
+ case Q_DEFAULT:
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 9, BPF_B, (long)v);
+ gen_and(b0, b1);
+ return b1;
+
+ case Q_ARP:
+ error("arp does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_RARP:
+ error("rarp does not encapsulate another protocol");
+ /* NOTREACHED */
+
+ case Q_LINK:
+ return gen_linktype(v);
+
+ case Q_UDP:
+ error("'udp proto' is bogus");
+
+ case Q_TCP:
+ error("'tcp proto' is bogus");
+
+ case Q_ICMP:
+ error("'icmp proto' is bogus");
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+struct block *
+gen_scode(name, q)
+ char *name;
+ struct qual q;
+{
+ int proto = q.proto;
+ int dir = q.dir;
+ u_char *eaddr;
+ u_long mask, addr, **alist;
+ struct block *b, *tmp;
+ int port, real_proto;
+
+ switch (q.addr) {
+
+ case Q_NET:
+ addr = s_nametonetaddr(name);
+ if (addr == 0)
+ error("unknown network '%s'", name);
+ mask = net_mask(&addr);
+ return gen_host(addr, mask, proto, dir);
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ if (proto == Q_LINK) {
+ /* XXX Should lookup hw addr based on link layer */
+ eaddr = ETHER_hostton(name);
+ if (eaddr == 0)
+ error("unknown ether host '%s'", name);
+ return gen_ehostop(eaddr, dir);
+
+ } else {
+ alist = s_nametoaddr(name);
+ if (alist == 0 || *alist == 0)
+ error("uknown host '%s'", name);
+ b = gen_host(**alist++, 0xffffffffL, proto, dir);
+ while (*alist) {
+ tmp = gen_host(**alist++, 0xffffffffL,
+ proto, dir);
+ gen_or(b, tmp);
+ b = tmp;
+ }
+ return b;
+ }
+
+ case Q_PORT:
+ if (proto != Q_DEFAULT && proto != Q_UDP && proto != Q_TCP)
+ error("illegal qualifier of 'port'");
+ if (s_nametoport(name, &port, &real_proto) == 0)
+ error("unknown port '%s'", name);
+ if (proto == Q_UDP) {
+ if (real_proto == IPPROTO_TCP)
+ error("port '%s' is tcp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_UDP;
+ }
+ if (proto == Q_TCP) {
+ if (real_proto == IPPROTO_UDP)
+ error("port '%s' is udp", name);
+ else
+ /* override PROTO_UNDEF */
+ real_proto = IPPROTO_TCP;
+ }
+ return gen_port(port, real_proto, dir);
+
+ case Q_GATEWAY:
+ eaddr = ETHER_hostton(name);
+ if (eaddr == 0)
+ error("unknown ether host: %s", name);
+
+ alist = s_nametoaddr(name);
+ if (alist == 0 || *alist == 0)
+ error("uknown host '%s'", name);
+ return gen_gateway(eaddr, alist, proto, dir);
+
+ case Q_PROTO:
+ real_proto = lookup_proto(name, proto);
+ if (real_proto >= 0)
+ return gen_proto(real_proto, proto, dir);
+ else
+ error("unknown protocol: %s", name);
+
+ case Q_UNDEF:
+ syntax();
+ /* NOTREACHED */
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+struct block *
+gen_ncode(v, q)
+ u_long v;
+ struct qual q;
+{
+ u_long mask;
+ int proto = q.proto;
+ int dir = q.dir;
+
+ switch (q.addr) {
+
+ case Q_DEFAULT:
+ case Q_HOST:
+ case Q_NET:
+ mask = net_mask(&v);
+ return gen_host(v, mask, proto, dir);
+
+ case Q_PORT:
+ if (proto == Q_UDP)
+ proto = IPPROTO_UDP;
+ else if (proto == Q_TCP)
+ proto = IPPROTO_TCP;
+ else if (proto == Q_DEFAULT)
+ proto = PROTO_UNDEF;
+ else
+ error("illegal qualifier of 'port'");
+
+ return gen_port((int)v, proto, dir);
+
+ case Q_GATEWAY:
+ error("'gateway' requires a name");
+ /* NOTREACHED */
+
+ case Q_PROTO:
+ return gen_proto((int)v, proto, dir);
+
+ case Q_UNDEF:
+ syntax();
+ /* NOTREACHED */
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+struct block *
+gen_ecode(eaddr, q)
+ u_char *eaddr;
+ struct qual q;
+{
+ if ((q.addr == Q_HOST || q.addr == Q_DEFAULT) && q.proto == Q_LINK)
+ return gen_ehostop(eaddr, (int)q.dir);
+ else
+ error("ethernet address used in non-ether expression");
+ /* NOTREACHED */
+}
+
+void
+sappend(s0, s1)
+ struct slist *s0, *s1;
+{
+ /*
+ * This is definitely not the best way to do this, but the
+ * lists will rarely get long.
+ */
+ while (s0->next)
+ s0 = s0->next;
+ s0->next = s1;
+}
+
+struct slist *
+xfer_to_x(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = new_stmt(BPF_LDX|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+struct slist *
+xfer_to_a(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_MEM);
+ s->s.k = a->regno;
+ return s;
+}
+
+struct arth *
+gen_load(proto, index, size)
+ int proto;
+ struct arth *index;
+ int size;
+{
+ struct slist *s, *tmp;
+ struct block *b;
+ int regno = alloc_reg();
+
+ free_reg(index->regno);
+ switch (size) {
+
+ default:
+ error("data size must be 1, 2, or 4");
+
+ case 1:
+ size = BPF_B;
+ break;
+
+ case 2:
+ size = BPF_H;
+ break;
+
+ case 4:
+ size = BPF_W;
+ break;
+ }
+ switch (proto) {
+ default:
+ error("unsupported index operation");
+
+ case Q_LINK:
+ s = xfer_to_x(index);
+ tmp = new_stmt(BPF_LD|BPF_IND|size);
+ sappend(s, tmp);
+ sappend(index->s, s);
+ break;
+
+ case Q_IP:
+ case Q_ARP:
+ case Q_RARP:
+ /* XXX Note that we assume a fixed link link header here. */
+ s = xfer_to_x(index);
+ tmp = new_stmt(BPF_LD|BPF_IND|size);
+ tmp->s.k = off_nl;
+ sappend(s, tmp);
+ sappend(index->s, s);
+
+ b = gen_proto_abbrev(proto);
+ if (index->b)
+ gen_and(index->b, b);
+ index->b = b;
+ break;
+
+ case Q_TCP:
+ case Q_UDP:
+ case Q_ICMP:
+ s = new_stmt(BPF_LDX|BPF_MSH|BPF_B);
+ s->s.k = off_nl;
+ sappend(s, xfer_to_a(index));
+ sappend(s, new_stmt(BPF_ALU|BPF_ADD|BPF_X));
+ sappend(s, new_stmt(BPF_MISC|BPF_TAX));
+ sappend(s, tmp = new_stmt(BPF_LD|BPF_IND|size));
+ tmp->s.k = off_nl;
+ sappend(index->s, s);
+
+ gen_and(gen_proto_abbrev(proto), b = gen_ipfrag());
+ if (index->b)
+ gen_and(index->b, b);
+ index->b = b;
+ break;
+ }
+ index->regno = regno;
+ s = new_stmt(BPF_ST);
+ s->s.k = regno;
+ sappend(index->s, s);
+
+ return index;
+}
+
+struct block *
+gen_relation(code, a0, a1, reversed)
+ int code;
+ struct arth *a0, *a1;
+ int reversed;
+{
+ struct slist *s0, *s1, *s2;
+ struct block *b, *tmp;
+
+ s0 = xfer_to_x(a1);
+ s1 = xfer_to_a(a0);
+ s2 = new_stmt(BPF_ALU|BPF_SUB|BPF_X);
+ b = new_block(JMP(code));
+ if (reversed)
+ gen_not(b);
+
+ sappend(s1, s2);
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ b->stmts = a0->s;
+
+ free_reg(a0->regno);
+ free_reg(a1->regno);
+
+ /* 'and' together protocol checks */
+ if (a0->b) {
+ if (a1->b) {
+ gen_and(a0->b, tmp = a1->b);
+ }
+ else
+ tmp = a0->b;
+ } else
+ tmp = a1->b;
+
+ if (tmp)
+ gen_and(tmp, b);
+
+ return b;
+}
+
+struct arth *
+gen_loadlen()
+{
+ int regno = alloc_reg();
+ struct arth *a = (struct arth *)newchunk(sizeof(*a));
+ struct slist *s;
+
+ s = new_stmt(BPF_LD|BPF_LEN);
+ s->next = new_stmt(BPF_ST);
+ s->next->s.k = regno;
+ a->s = s;
+ a->regno = regno;
+
+ return a;
+}
+
+struct arth *
+gen_loadi(val)
+ int val;
+{
+ struct arth *a;
+ struct slist *s;
+ int reg;
+
+ a = (struct arth *)newchunk(sizeof(*a));
+
+ reg = alloc_reg();
+
+ s = new_stmt(BPF_LD|BPF_IMM);
+ s->s.k = val;
+ s->next = new_stmt(BPF_ST);
+ s->next->s.k = reg;
+ a->s = s;
+ a->regno = reg;
+
+ return a;
+}
+
+struct arth *
+gen_neg(a)
+ struct arth *a;
+{
+ struct slist *s;
+
+ s = xfer_to_a(a);
+ sappend(a->s, s);
+ s = new_stmt(BPF_ALU|BPF_NEG);
+ s->s.k = 0;
+ sappend(a->s, s);
+ s = new_stmt(BPF_ST);
+ s->s.k = a->regno;
+ sappend(a->s, s);
+
+ return a;
+}
+
+struct arth *
+gen_arth(code, a0, a1)
+ int code;
+ struct arth *a0, *a1;
+{
+ struct slist *s0, *s1, *s2;
+
+ s0 = xfer_to_x(a1);
+ s1 = xfer_to_a(a0);
+ s2 = new_stmt(BPF_ALU|BPF_X|code);
+
+ sappend(s1, s2);
+ sappend(s0, s1);
+ sappend(a1->s, s0);
+ sappend(a0->s, a1->s);
+
+ free_reg(a1->regno);
+
+ s0 = new_stmt(BPF_ST);
+ a0->regno = s0->s.k = alloc_reg();
+ sappend(a0->s, s0);
+
+ return a0;
+}
+
+/*
+ * Here we handle simple allocation of the scratch registers.
+ * If too many registers are alloc'd, the allocator punts.
+ */
+static int regused[BPF_MEMWORDS];
+static int curreg;
+
+/*
+ * Return the next free register.
+ */
+static int
+alloc_reg()
+{
+ int n = BPF_MEMWORDS;
+
+ while (--n >= 0) {
+ if (regused[curreg])
+ curreg = (curreg + 1) % BPF_MEMWORDS;
+ else {
+ regused[curreg] = 1;
+ return curreg;
+ }
+ }
+ error("too many registers needed to evaluate expression");
+ /* NOTREACHED */
+}
+
+/*
+ * Return a register to the table so it can
+ * be used later.
+ */
+static void
+free_reg(n)
+ int n;
+{
+ regused[n] = 0;
+}
+
+static struct block *
+gen_len(jmp, n)
+ int jmp;
+ int n;
+{
+ struct slist *s;
+ struct block *b;
+
+ s = new_stmt(BPF_LD|BPF_LEN);
+ s->next = new_stmt(BPF_SUB|BPF_IMM);
+ s->next->s.k = n;
+ b = new_block(JMP(jmp));
+ b->stmts = s;
+
+ return b;
+}
+
+struct block *
+gen_greater(n)
+ int n;
+{
+ return gen_len(BPF_JGE, n);
+}
+
+struct block *
+gen_less(n)
+ int n;
+{
+ struct block *b;
+
+ b = gen_len(BPF_JGT, n);
+ gen_not(b);
+
+ return b;
+}
+
+struct block *
+gen_byteop(op, idx, val)
+ int op;
+ int idx;
+ int val;
+{
+ struct block *b;
+ struct slist *s;
+
+ switch (op) {
+ default:
+ abort();
+
+ case '=':
+ return gen_cmp((u_int)idx, BPF_B, (long)val);
+
+ case '<':
+ b = gen_cmp((u_int)idx, BPF_B, (long)val);
+ b->s.code = JMP(BPF_JGE);
+ gen_not(b);
+ return b;
+
+ case '>':
+ b = gen_cmp((u_int)idx, BPF_B, (long)val);
+ b->s.code = JMP(BPF_JGT);
+ return b;
+
+ case '|':
+ s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ break;
+
+ case '&':
+ s = new_stmt(BPF_ALU|BPF_AND|BPF_K);
+ break;
+ }
+ s->s.k = val;
+ b = new_block(JMP(BPF_JEQ));
+ b->stmts = s;
+ gen_not(b);
+
+ return b;
+}
+
+struct block *
+gen_broadcast(proto)
+ int proto;
+{
+ u_long hostmask;
+ struct block *b0, *b1, *b2;
+ static u_char ebroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ if (linktype == DLT_EN10MB)
+ return gen_ehostop(ebroadcast, Q_DST);
+ error("not a broadcast link");
+ break;
+
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ hostmask = ~netmask;
+ b1 = gen_mcmp(off_nl + 16, BPF_W, (long)0, hostmask);
+ b2 = gen_mcmp(off_nl + 16, BPF_W,
+ (long)(~0 & hostmask), hostmask);
+ gen_or(b1, b2);
+ gen_and(b0, b2);
+ return b2;
+ }
+ error("only ether/ip broadcast filters supported");
+}
+
+struct block *
+gen_multicast(proto)
+ int proto;
+{
+ register struct block *b0, *b1, *b2;
+ register struct slist *s;
+
+ switch (proto) {
+
+ case Q_DEFAULT:
+ case Q_LINK:
+ if (linktype != DLT_EN10MB)
+ break;
+
+ /* ether[0] & 1 != 0 */
+ s = new_stmt(BPF_LD|BPF_B|BPF_ABS);
+ s->s.k = 0;
+ b0 = new_block(JMP(BPF_JSET));
+ b0->s.k = 1;
+ b0->stmts = s;
+ return b0;
+
+ case Q_IP:
+ b0 = gen_linktype(ETHERTYPE_IP);
+ b1 = gen_cmp(off_nl + 16, BPF_B, (long)224);
+ b1->s.code = JMP(BPF_JGE);
+ gen_and(b0, b1);
+ return b1;
+ }
+ error("only ether/ip multicast filters supported");
+}
diff --git a/usr.sbin/tcpdump/tcpdump/gencode.h b/usr.sbin/tcpdump/tcpdump/gencode.h
new file mode 100644
index 0000000..b8f342d
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/gencode.h
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: gencode.h,v 1.14 92/02/14 15:18:55 mccanne Exp $ (LBL)
+ */
+
+/*
+ * filter.h must be included before this file.
+ */
+
+/* Address qualifers. */
+
+#define Q_HOST 1
+#define Q_NET 2
+#define Q_PORT 3
+#define Q_GATEWAY 4
+#define Q_PROTO 5
+
+/* Protocol qualifiers. */
+
+#define Q_LINK 1
+#define Q_IP 2
+#define Q_ARP 3
+#define Q_RARP 4
+#define Q_TCP 5
+#define Q_UDP 6
+#define Q_ICMP 7
+
+/* Directional qualifers. */
+
+#define Q_SRC 1
+#define Q_DST 2
+#define Q_OR 3
+#define Q_AND 4
+
+#define Q_DEFAULT 0
+#define Q_UNDEF 255
+
+struct stmt {
+ int code;
+ long k;
+};
+
+struct slist {
+ struct stmt s;
+ struct slist *next;
+};
+
+/*
+ * A bit vector to represent definition sets. We assume TOT_REGISTERS
+ * is smaller than 8*sizeof(atomset).
+ */
+typedef u_long atomset;
+#define ATOMMASK(n) (1 << (n))
+#define ATOMELEM(d, n) (d & ATOMMASK(n))
+
+/*
+ * An unbounded set.
+ */
+typedef u_long *uset;
+
+/*
+ * Total number of atomic entities, including accumulator (A) and index (X).
+ * We treat all these guys similarly during flow analysis.
+ */
+#define N_ATOMS (BPF_MEMWORDS+2)
+
+struct edge {
+ int id;
+ int code;
+ uset edom;
+ struct block *succ;
+ struct block *pred;
+ struct edge *next; /* link list of incoming edges for a node */
+};
+
+struct block {
+ int id;
+ struct slist *stmts; /* side effect stmts */
+ struct stmt s; /* branch stmt */
+ int mark;
+ int level;
+ int offset;
+ int sense;
+ struct edge et;
+ struct edge ef;
+ struct block *head;
+ struct block *link; /* link field used by optimizer */
+ uset dom;
+ uset closure;
+ struct edge *in_edges;
+ atomset def, kill;
+ atomset in_use;
+ atomset out_use;
+ long oval;
+ long val[N_ATOMS];
+};
+
+struct arth {
+ struct block *b; /* protocol checks */
+ struct slist *s; /* stmt list */
+ int regno; /* virtual register number of result */
+};
+
+extern struct arth *gen_loadi();
+extern struct arth *gen_load();
+extern struct arth *gen_loadlen();
+extern struct arth *gen_neg();
+extern struct arth *gen_arth();
+
+extern void gen_and();
+extern void gen_or();
+extern void gen_not();
+
+extern struct block *gen_scode();
+extern struct block *gen_ecode();
+extern struct block *gen_ncode();
+extern struct block *gen_proto_abbrev();
+extern struct block *gen_relation();
+extern struct block *gen_less();
+extern struct block *gen_greater();
+extern struct block *gen_byteop();
+extern struct block *gen_broadcast();
+extern struct block *gen_multicast();
+
+extern void optimize();
+
+extern void finish_parse();
+
+struct qual {
+ unsigned char addr;
+ unsigned char proto;
+ unsigned char dir;
+ unsigned char pad;
+};
+
+/* XXX */
+#define JT(b) ((b)->et.succ)
+#define JF(b) ((b)->ef.succ)
diff --git a/usr.sbin/tcpdump/tcpdump/inet.c b/usr.sbin/tcpdump/tcpdump/inet.c
new file mode 100644
index 0000000..550129e
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/inet.c
@@ -0,0 +1,172 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: inet.c,v 1.12 92/01/29 12:46:18 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "interface.h"
+
+/* Not all systems have IFF_LOOPBACK */
+#ifdef IFF_LOOPBACK
+#define ISLOOPBACK(p) ((p)->ifr_flags & IFF_LOOPBACK)
+#else
+#define ISLOOPBACK(p) (strcmp((p)->ifr_name, "lo0") == 0)
+#endif
+
+/*
+ * 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.
+ */
+char *
+lookup_device()
+{
+ struct ifreq ibuf[16], *ifrp, *ifend, *mp;
+ struct ifconf ifc;
+ int fd;
+ int minunit, n;
+ char *cp;
+ static char device[sizeof(ifrp->ifr_name)];
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ perror("tcpdump: socket");
+ exit(1);
+ }
+ ifc.ifc_len = sizeof ibuf;
+ ifc.ifc_buf = (caddr_t)ibuf;
+
+ if (ioctl(fd, SIOCGIFCONF, (char *)&ifc) < 0 ||
+ ifc.ifc_len < sizeof(struct ifreq)) {
+ perror("tcpdump: SIOCGIFCONF: ");
+ exit(1);
+ }
+ ifrp = ibuf;
+ ifend = (struct ifreq *)((char *)ibuf + ifc.ifc_len);
+
+ mp = 0;
+ minunit = 666;
+ while (ifrp < ifend) {
+ struct ifreq ifr;
+ /*
+ * 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));
+ if (ioctl(fd, SIOCGIFFLAGS, (char *)&ifr) < 0) {
+ fprintf(stderr, "tcpdump: SIOCGIFFLAGS: ");
+ perror(ifrp->ifr_name);
+ exit(1);
+ }
+ if ((ifr.ifr_flags & IFF_UP) && !ISLOOPBACK(&ifr)) {
+ for (cp = ifrp->ifr_name; !isdigit(*cp); ++cp)
+ ;
+ n = atoi(cp);
+ if (n < minunit) {
+ minunit = n;
+ mp = ifrp;
+ }
+ }
+#if 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
+ }
+ close(fd);
+ if (mp == 0)
+ return (0);
+
+ (void)strcpy(device, mp->ifr_name);
+ return (device);
+}
+
+/*
+ * Get the netmask of an IP address. This routine is used if
+ * SIOCGIFNETMASK doesn't work.
+ */
+static 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);
+ error("unknown IP address class: %08X", addr);
+ /* NOTREACHED */
+}
+
+void
+lookup_net(device, netp, maskp)
+ char *device;
+ u_long *netp;
+ u_long *maskp;
+{
+ int fd;
+ struct ifreq ifr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+
+ /* Use data gram socket to get IP address. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("tcpdump: socket");
+ exit(1);
+ }
+ (void)strncpy(ifr.ifr_name, device, sizeof ifr.ifr_name);
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) < 0) {
+ /*
+ * This will fail if an IP address hasn't been assigned.
+ */
+ *netp = 0;
+ *maskp = 0;
+ return;
+ }
+ *netp = sin->sin_addr.s_addr;
+ if (ioctl(fd, SIOCGIFNETMASK, (char *)&ifr) < 0)
+ *maskp = 0;
+ else
+ *maskp = sin->sin_addr.s_addr;
+ if (*maskp == 0)
+ *maskp = ipaddrtonetmask(*netp);
+ *netp &= *maskp;
+ (void)close(fd);
+}
diff --git a/usr.sbin/tcpdump/tcpdump/interface.h b/usr.sbin/tcpdump/tcpdump/interface.h
new file mode 100644
index 0000000..1ff89ff
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/interface.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/interface.h,v 1.1.1.1 1993/06/12 14:42:12 rgrimes Exp $ (LBL)
+ */
+
+#ifdef __GNUC__
+#ifndef inline
+#define inline __inline
+#endif
+#else
+#define inline
+#endif
+
+#include "os.h" /* operating system stuff */
+#include "md.h" /* machine dependent stuff */
+
+#ifndef __STDC__
+extern char *malloc();
+extern char *calloc();
+#endif
+
+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 unsigned char *packetp;
+extern unsigned char *snapend;
+
+extern long thiszone; /* gmt to local correction */
+
+extern void ts_print();
+extern int clock_sigfigs();
+
+extern char *lookup_device();
+
+extern void error();
+extern void warning();
+
+extern char *read_infile();
+extern char *copy_argv();
+
+extern void usage();
+extern void show_code();
+extern void init_addrtoname();
+
+/* The printer routines. */
+
+extern void ether_if_print();
+extern void arp_print();
+extern void ip_print();
+extern void tcp_print();
+extern void udp_print();
+extern void icmp_print();
+extern void default_print();
+
+extern void ntp_print();
+extern void nfsreq_print();
+extern void nfsreply_print();
+extern void ns_print();
+extern void ddp_print();
+extern void rip_print();
+extern void tftp_print();
+extern void bootp_print();
+extern void snmp_print();
+extern void sl_if_print();
+extern void ppp_if_print();
+extern void fddi_if_print();
+extern void null_if_print();
+extern void egp_print();
+
+#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/tcpdump/md.c b/usr.sbin/tcpdump/tcpdump/md.c
new file mode 100644
index 0000000..6bb04b7
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/md.c
@@ -0,0 +1,35 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#) $Header: md-vax.c,v 1.3 90/10/03 14:14:33 mccanne Locked $ (LBL)";
+#endif
+
+/* Vaxen appear to have clocks accurate to 1 us,
+ but packetfilter is timestamping to 10 ms. */
+
+int
+clock_sigfigs()
+{
+ return 2;
+}
+
diff --git a/usr.sbin/tcpdump/tcpdump/md.h b/usr.sbin/tcpdump/tcpdump/md.h
new file mode 100644
index 0000000..f83d81f
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/md.h
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: md-vax.h,v 1.2 90/09/21 02:23:16 mccanne Exp $ (LBL)
+ */
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+/* These should be fixed to be real macros, for speed */
+
+#ifndef NTOHL
+#define NTOHL(x) (x) = ntohl(x)
+#define NTOHS(x) (x) = ntohs(x)
+#define HTONL(x) (x) = htonl(x)
+#define HTONS(x) (x) = htons(x)
+#endif
+
+#ifndef vax
+/* Some Ultrix header files may need this */
+#define vax 1
+#endif vax
diff --git a/usr.sbin/tcpdump/tcpdump/mib.h b/usr.sbin/tcpdump/tcpdump/mib.h
new file mode 100644
index 0000000..a81897c
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/mib.h
@@ -0,0 +1,1256 @@
+/*
+ * 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/tcpdump/nametoaddr.c b/usr.sbin/tcpdump/tcpdump/nametoaddr.c
new file mode 100644
index 0000000..6f2330f
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/nametoaddr.c
@@ -0,0 +1,258 @@
+/*
+ * 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.
+ *
+ * Name to id translation routines used by the scanner.
+ * These functions are not time critical.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: nametoaddr.c,v 1.9 91/02/04 16:56:46 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+#include <errno.h>
+#include <arpa/inet.h>
+
+#ifdef ultrix
+#include <sys/time.h>
+#include <rpc/types.h>
+#include <nfs/nfs.h>
+#endif
+
+#include "interface.h"
+#include "etherent.h"
+#include "nametoaddr.h"
+
+/*
+ * Convert host name to internet address.
+ * Return 0 upon failure.
+ */
+u_long **
+s_nametoaddr(name)
+ char *name;
+{
+#ifndef h_addr
+ static u_long *hlist[2];
+#endif
+ u_long **p;
+ struct hostent *hp;
+
+ if (hp = gethostbyname(name)) {
+#ifndef h_addr
+ hlist[0] = (u_long *)hp->h_addr;
+ NTOHL(hp->h_addr);
+ return hlist;
+#else
+ for (p = (u_long **)hp->h_addr_list; *p; ++p)
+ NTOHL(**p);
+ return (u_long **)hp->h_addr_list;
+#endif
+ }
+ else
+ return 0;
+}
+
+/*
+ * Convert net name to internet address.
+ * Return 0 upon failure.
+ */
+u_long
+s_nametonetaddr(name)
+ char *name;
+{
+ struct netent *np;
+
+ if (np = getnetbyname(name))
+ return np->n_net;
+ else
+ return 0;
+}
+
+/*
+ * Convert a port name to its port and protocol numbers.
+ * We assume only TCP or UDP.
+ * Return 0 upon failure.
+ */
+s_nametoport(name, port, proto)
+ char *name;
+ int *port;
+ int *proto;
+{
+ struct servent *sp;
+ char *other;
+
+ sp = getservbyname(name, (char *)0);
+ if (sp != 0) {
+ NTOHS(sp->s_port);
+ *port = sp->s_port;
+ *proto = s_nametoproto(sp->s_proto);
+ /*
+ * We need to check /etc/services for ambiguous entries.
+ * If we find the ambiguous entry, and it has the
+ * same port number, change the proto to PROTO_UNDEF
+ * so both TCP and UDP will be checked.
+ */
+ if (*proto == IPPROTO_TCP)
+ other = "udp";
+ else
+ other = "tcp";
+
+ sp = getservbyname(name, other);
+ if (sp != 0) {
+ NTOHS(sp->s_port);
+ if (*port != sp->s_port)
+ /* Can't handle ambigous names that refer
+ to different port numbers. */
+ warning("ambiguous port %s in /etc/services",
+ name);
+ *proto = PROTO_UNDEF;
+ }
+ return 1;
+ }
+#ifdef ultrix
+ /* Special hack in case NFS isn't in /etc/services */
+ if (strcmp(name, "nfs") == 0) {
+ *port = NFS_PORT;
+ *proto = PROTO_UNDEF;
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+int
+s_nametoproto(str)
+ char *str;
+{
+ struct protoent *p;
+
+ p = getprotobyname(str);
+ if (p != 0)
+ return p->p_proto;
+ else
+ return PROTO_UNDEF;
+}
+
+#include "etherproto.h"
+
+int
+s_nametoeproto(s)
+ char *s;
+{
+ struct eproto *p = eproto_db;
+
+ while (p->s != 0) {
+ if (strcmp(p->s, s) == 0)
+ return p->p;
+ p += 1;
+ }
+ return PROTO_UNDEF;
+}
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+u_long
+atoin(s)
+ char *s;
+{
+ u_long addr = 0;
+ u_int n;
+
+ while (1) {
+ n = 0;
+ while (*s && *s != '.')
+ n = n * 10 + *s++ - '0';
+ addr <<= 8;
+ addr |= n & 0xff;
+ if (*s == '\0')
+ return addr;
+ ++s;
+ }
+ /* NOTREACHED */
+}
+
+
+/*
+ * Convert 's' which has the form "xx:xx:xx:xx:xx:xx" into a new
+ * ethernet address. Assumes 's' is well formed.
+ */
+u_char *
+ETHER_aton(s)
+ char *s;
+{
+ register u_char *ep, *e;
+ register u_int d;
+
+ e = ep = (u_char *)malloc(6);
+
+ while (*s) {
+ if (*s == ':')
+ s += 1;
+ d = xdtoi(*s++);
+ if (isxdigit(*s)) {
+ d <<= 4;
+ d |= xdtoi(*s++);
+ }
+ *ep++ = d;
+ }
+
+ return e;
+}
+
+#ifndef ETHER_SERVICE
+u_char *
+ETHER_hostton(name)
+ char *name;
+{
+ struct etherent *ep;
+ FILE *fp;
+ u_char *ap;
+
+ fp = fopen(ETHERS_FILE, "r");
+ if (fp != 0) {
+ while (ep = next_etherent(fp)) {
+ if (strcmp(ep->name, name) == 0) {
+ ap = (u_char *)malloc(6);
+ bcopy(ep->addr, ap, 6);
+ return ap;
+ }
+ }
+ }
+ return (u_char *)0;
+}
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/nametoaddr.h b/usr.sbin/tcpdump/tcpdump/nametoaddr.h
new file mode 100644
index 0000000..23da3f2
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/nametoaddr.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: nametoaddr.h,v 1.6 90/09/24 12:50:41 mccanne Exp $ (LBL)
+ *
+ * Address to name translation routines.
+ */
+
+extern u_long **s_nametoaddr();
+extern u_long s_nametonetaddr();
+
+extern int s_nametoport();
+extern int s_nametoproto();
+extern int s_nametoeproto();
+
+extern u_char *ETHER_hostton();
+extern u_char *ETHER_aton();
+
+/*
+ * If a protocol is unknown, PROTO_UNDEF is returned.
+ * Also, s_nametoport() returns the protocol along with the port number.
+ * If there are ambiguous entried in /etc/services (i.e. domain
+ * can be either tcp or udp) PROTO_UNDEF is returned.
+ */
+#define PROTO_UNDEF -1
+
diff --git a/usr.sbin/tcpdump/tcpdump/ntp.h b/usr.sbin/tcpdump/tcpdump/ntp.h
new file mode 100644
index 0000000..493686d
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/ntp.h
@@ -0,0 +1,117 @@
+/* $Header: ntp.h,v 1.1 90/08/07 11:08:27 mogul 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_long int_part;
+ u_long 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_long 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/tcpdump/optimize.c b/usr.sbin/tcpdump/tcpdump/optimize.c
new file mode 100644
index 0000000..5064011
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/optimize.c
@@ -0,0 +1,1871 @@
+/*
+ * 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.
+ *
+ * Optimization module for tcpdump intermediate representation.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: optimize.c,v 1.35 91/07/18 09:27:55 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "gencode.h"
+
+#define A_ATOM BPF_MEMWORDS
+#define X_ATOM (BPF_MEMWORDS+1)
+
+#define NOP -1
+
+/*
+ * This define is used to represent *both* the accumulator and
+ * x register in use-def computations.
+ * Currently, the use-def code assumes only one definition per instruction.
+ */
+#define AX_ATOM N_ATOMS
+
+/*
+ * A flag to indicate that further optimization is needed.
+ * Iterative passes are continued until a given pass yields no
+ * branch movement.
+ */
+static int done;
+
+/*
+ * A block is marked if only if its mark equals the current mark.
+ * Rather than traverse the code array, marking each item, 'cur_mark' is
+ * incremented. This automatically makes each element unmarked.
+ */
+static int cur_mark;
+#define isMarked(p) ((p)->mark == cur_mark)
+#define unMarkAll() cur_mark += 1
+#define Mark(p) ((p)->mark = cur_mark)
+
+static void opt_init();
+static void opt_cleanup();
+
+static void make_marks();
+static void mark_code();
+
+static void intern_blocks();
+
+static int eq_slist();
+
+static int n_blocks;
+struct block **blocks;
+static int n_edges;
+struct edge **edges;
+
+/*
+ * A bit vector set representation of the dominators.
+ * We round up the set size to the next power of two.
+ */
+static int nodewords;
+static int edgewords;
+struct block **levels;
+u_long *space;
+#define BITS_PER_WORD (8*sizeof(u_long))
+/*
+ * True if a is in uset {p}
+ */
+#define SET_MEMBER(p, a) \
+((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
+
+/*
+ * Add 'a' to uset p.
+ */
+#define SET_INSERT(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * Delete 'a' from uset p.
+ */
+#define SET_DELETE(p, a) \
+(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
+
+/*
+ * a := a intersect b
+ */
+#define SET_INTERSECT(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ &= *_y++;\
+}
+
+/*
+ * a := a - b
+ */
+#define SET_SUBTRACT(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ &=~ *_y++;\
+}
+
+/*
+ * a := a union b
+ */
+#define SET_UNION(a, b, n)\
+{\
+ register u_long *_x = a, *_y = b;\
+ register int _n = n;\
+ while (--_n >= 0) *_x++ |= *_y++;\
+}
+
+static uset all_dom_sets;
+static uset all_closure_sets;
+static uset all_edge_sets;
+
+#ifndef MAX
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#endif
+
+static void
+find_levels_r(b)
+ struct block *b;
+{
+ int level;
+
+ if (isMarked(b))
+ return;
+
+ Mark(b);
+ b->link = 0;
+
+ if (JT(b)) {
+ find_levels_r(JT(b));
+ find_levels_r(JF(b));
+ level = MAX(JT(b)->level, JF(b)->level) + 1;
+ } else
+ level = 0;
+ b->level = level;
+ b->link = levels[level];
+ levels[level] = b;
+}
+
+/*
+ * Level graph. The levels go from 0 at the leaves to
+ * N_LEVELS at the root. The levels[] array points to the
+ * first node of the level list, whose elements are linked
+ * with the 'link' field of the struct block.
+ */
+static void
+find_levels(root)
+ struct block *root;
+{
+ bzero((char *)levels, n_blocks * sizeof(*levels));
+ unMarkAll();
+ find_levels_r(root);
+}
+
+/*
+ * Find dominator relationships.
+ * Assumes graph has been leveled.
+ */
+static void
+find_dom(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+ u_long *x;
+
+ /*
+ * Initialize sets to contain all nodes.
+ */
+ x = all_dom_sets;
+ i = n_blocks * nodewords;
+ while (--i >= 0)
+ *x++ = ~0;
+ /* Root starts off empty. */
+ for (i = nodewords; --i >= 0;)
+ root->dom[i] = 0;
+
+ /* root->level is the highest level no found. */
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b; b = b->link) {
+ SET_INSERT(b->dom, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_INTERSECT(JT(b)->dom, b->dom, nodewords);
+ SET_INTERSECT(JF(b)->dom, b->dom, nodewords);
+ }
+ }
+}
+
+static void
+propedom(ep)
+ struct edge *ep;
+{
+ SET_INSERT(ep->edom, ep->id);
+ if (ep->succ) {
+ SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords);
+ SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords);
+ }
+}
+
+/*
+ * Compute edge dominators.
+ * Assumes graph has been leveled and predecessors estabished.
+ */
+static void
+find_edom(root)
+ struct block *root;
+{
+ int i;
+ uset x;
+ struct block *b;
+
+ x = all_edge_sets;
+ for (i = n_edges * edgewords; --i >= 0; )
+ x[i] = ~0;
+
+ /* root->level is the highest level no found. */
+ bzero(root->et.edom, edgewords * sizeof(*(uset)0));
+ bzero(root->ef.edom, edgewords * sizeof(*(uset)0));
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b != 0; b = b->link) {
+ propedom(&b->et);
+ propedom(&b->ef);
+ }
+ }
+}
+
+/*
+ * Find the backwards transitive closure of the flow graph. These sets
+ * are backwards in the sense that we find the set of nodes that reach
+ * a given node, not the set of nodes that can be reached by a node.
+ *
+ * Assumes graph has been leveled.
+ */
+static void
+find_closure(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+
+ /*
+ * Initialize sets to contain no nodes.
+ */
+ bzero((char *)all_closure_sets,
+ n_blocks * nodewords * sizeof(*all_closure_sets));
+
+ /* root->level is the highest level no found. */
+ for (i = root->level; i >= 0; --i) {
+ for (b = levels[i]; b; b = b->link) {
+ SET_INSERT(b->closure, b->id);
+ if (JT(b) == 0)
+ continue;
+ SET_UNION(JT(b)->closure, b->closure, nodewords);
+ SET_UNION(JF(b)->closure, b->closure, nodewords);
+ }
+ }
+}
+
+/*
+ * Return the register number that is used by s. If A and X are both
+ * used, return AX_ATOM. If no register is used, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomuse(s)
+ struct stmt *s;
+{
+ register int c = s->code;
+
+ if (c == NOP)
+ return -1;
+
+ switch (BPF_CLASS(c)) {
+
+ case BPF_RET:
+ return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
+ (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
+
+ case BPF_LD:
+ case BPF_LDX:
+ return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
+ (BPF_MODE(c) == BPF_MEM) ? s->k : -1;
+
+ case BPF_ST:
+ return A_ATOM;
+
+ case BPF_STX:
+ return X_ATOM;
+
+ case BPF_JMP:
+ case BPF_ALU:
+ if (BPF_SRC(c) == BPF_X)
+ return AX_ATOM;
+ return A_ATOM;
+
+ case BPF_MISC:
+ return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
+ }
+ abort();
+ /* NOTREACHED */
+}
+
+/*
+ * Return the register number that is defined by 's'. We assume that
+ * a single stmt cannot define more than one register. If no register
+ * is defined, return -1.
+ *
+ * The implementation should probably change to an array access.
+ */
+static int
+atomdef(s)
+ struct stmt *s;
+{
+ if (s->code == NOP)
+ return -1;
+
+ switch (BPF_CLASS(s->code)) {
+
+ case BPF_LD:
+ case BPF_ALU:
+ return A_ATOM;
+
+ case BPF_LDX:
+ return X_ATOM;
+
+ case BPF_ST:
+ case BPF_STX:
+ return s->k;
+
+ case BPF_MISC:
+ return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
+ }
+ return -1;
+}
+
+static void
+compute_local_ud(b)
+ struct block *b;
+{
+ struct slist *s;
+ atomset def = 0, use = 0, kill = 0;
+ int atom;
+
+ for (s = b->stmts; s; s = s->next) {
+ if (s->s.code == NOP)
+ continue;
+ atom = atomuse(&s->s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ if (!ATOMELEM(def, X_ATOM))
+ use |= ATOMMASK(X_ATOM);
+ if (!ATOMELEM(def, A_ATOM))
+ use |= ATOMMASK(A_ATOM);
+ }
+ else if (atom < N_ATOMS) {
+ if (!ATOMELEM(def, atom))
+ use |= ATOMMASK(atom);
+ }
+ else
+ abort();
+ }
+ atom = atomdef(&s->s);
+ if (atom >= 0) {
+ if (!ATOMELEM(atom, use))
+ kill |= ATOMMASK(atom);
+ def |= ATOMMASK(atom);
+ }
+ }
+ if (!ATOMELEM(def, A_ATOM) && BPF_CLASS(b->s.code) == BPF_JMP)
+ use |= ATOMMASK(A_ATOM);
+
+ b->def = def;
+ b->kill = kill;
+ b->in_use = use;
+}
+
+/*
+ * Assume graph is already leveled.
+ */
+static void
+find_ud(root)
+ struct block *root;
+{
+ int i, maxlevel;
+ struct block *p;
+
+ /*
+ * root->level is the highest level no found;
+ * count down from there.
+ */
+ maxlevel = root->level;
+ for (i = maxlevel; i >= 0; --i)
+ for (p = levels[i]; p; p = p->link) {
+ compute_local_ud(p);
+ p->out_use = 0;
+ }
+
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ p->out_use |= JT(p)->in_use | JF(p)->in_use;
+ p->in_use |= p->out_use &~ p->kill;
+ }
+ }
+}
+
+/*
+ * These data structures are used in a Cocke and Shwarz style
+ * value numbering scheme. Since the flowgraph is acyclic,
+ * exit values can be propagated from a node's predecessors
+ * provided it is uniquely defined.
+ */
+struct valnode {
+ int code;
+ long v0, v1;
+ long val;
+ struct valnode *next;
+};
+
+#define MODULUS 213
+static struct valnode *hashtbl[MODULUS];
+static int curval;
+static int maxval;
+
+/* Integer constants mapped with the load immediate opcode. */
+#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)
+
+struct vmapinfo {
+ int is_const;
+ long const_val;
+};
+
+struct vmapinfo *vmap;
+struct valnode *vnode_base;
+struct valnode *next_vnode;
+
+static void
+init_val()
+{
+ curval = 0;
+ next_vnode = vnode_base;
+ bzero((char *)vmap, maxval * sizeof(*vmap));
+ bzero((char *)hashtbl, sizeof hashtbl);
+}
+
+/* Because we really don't have an IR, this stuff is a little messy. */
+static long
+F(code, v0, v1)
+ int code;
+ long v0, v1;
+{
+ u_int hash;
+ int val;
+ struct valnode *p;
+
+ hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
+ hash %= MODULUS;
+
+ for (p = hashtbl[hash]; p; p = p->next)
+ if (p->code == code && p->v0 == v0 && p->v1 == v1)
+ return p->val;
+
+ val = ++curval;
+ if (BPF_MODE(code) == BPF_IMM &&
+ (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
+ vmap[val].const_val = v0;
+ vmap[val].is_const = 1;
+ }
+ p = next_vnode++;
+ p->val = val;
+ p->code = code;
+ p->v0 = v0;
+ p->v1 = v1;
+ p->next = hashtbl[hash];
+ hashtbl[hash] = p;
+
+ return val;
+}
+
+static inline void
+vstore(s, valp, newval, alter)
+ struct stmt *s;
+ long *valp;
+ long newval;
+ int alter;
+{
+ if (alter && *valp == newval)
+ s->code = NOP;
+ else
+ *valp = newval;
+}
+
+static void
+fold_op(s, v0, v1)
+ struct stmt *s;
+ long v0, v1;
+{
+ long a, b;
+
+ a = vmap[v0].const_val;
+ b = vmap[v1].const_val;
+
+ switch (BPF_OP(s->code)) {
+ case BPF_ADD:
+ a += b;
+ break;
+
+ case BPF_SUB:
+ a -= b;
+ break;
+
+ case BPF_MUL:
+ a *= b;
+ break;
+
+ case BPF_DIV:
+ if (b == 0)
+ error("division by zero");
+ a /= b;
+ break;
+
+ case BPF_AND:
+ a &= b;
+ break;
+
+ case BPF_OR:
+ a |= b;
+ break;
+
+ case BPF_LSH:
+ a <<= b;
+ break;
+
+ case BPF_RSH:
+ a >>= b;
+ break;
+
+ case BPF_NEG:
+ a = -a;
+ break;
+
+ default:
+ abort();
+ }
+ s->k = a;
+ s->code = BPF_LD|BPF_IMM;
+ done = 0;
+}
+
+static inline struct slist *
+this_op(s)
+ struct slist *s;
+{
+ while (s != 0 && s->s.code == NOP)
+ s = s->next;
+ return s;
+}
+
+static void
+opt_not(b)
+ struct block *b;
+{
+ struct block *tmp = JT(b);
+
+ JT(b) = JF(b);
+ JF(b) = tmp;
+}
+
+static void
+opt_peep(b)
+ struct block *b;
+{
+ struct slist *s;
+ struct slist *next, *last;
+ int val;
+ long v;
+
+ s = b->stmts;
+ if (s == 0)
+ return;
+
+ last = s;
+ while (1) {
+ s = this_op(s);
+ if (s == 0)
+ break;
+ next = this_op(s->next);
+ if (next == 0)
+ break;
+ last = next;
+
+ /*
+ * st M[k] --> st M[k]
+ * ldx M[k] tax
+ */
+ if (s->s.code == BPF_ST &&
+ next->s.code == (BPF_LDX|BPF_MEM) &&
+ s->s.k == next->s.k) {
+ done = 0;
+ next->s.code = BPF_MISC|BPF_TAX;
+ }
+ /*
+ * ld #k --> ldx #k
+ * tax txa
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM) &&
+ next->s.code == (BPF_MISC|BPF_TAX)) {
+ s->s.code = BPF_LDX|BPF_IMM;
+ next->s.code = BPF_MISC|BPF_TXA;
+ done = 0;
+ }
+ /*
+ * This is an ugly special case, but it happens
+ * when you say tcp[k] or udp[k] where k is a constant.
+ */
+ if (s->s.code == (BPF_LD|BPF_IMM)) {
+ struct slist *add, *tax, *ild;
+
+ /*
+ * Check that X isn't used on exit from this
+ * block (which the optimizer might cause).
+ * We know the code generator won't generate
+ * any local dependencies.
+ */
+ if (ATOMELEM(b->out_use, X_ATOM))
+ break;
+
+ if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
+ add = next;
+ else
+ add = this_op(next->next);
+ if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
+ break;
+
+ tax = this_op(add->next);
+ if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
+ break;
+
+ ild = this_op(tax->next);
+ if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
+ BPF_MODE(ild->s.code) != BPF_IND)
+ break;
+ /*
+ * XXX We need to check that X is not
+ * subsequently used. We know we can eliminate the
+ * accumulator modifications since it is defined
+ * by the last stmt of this sequence.
+ *
+ * We want to turn this sequence:
+ *
+ * (004) ldi #0x2 {s}
+ * (005) ldxms [14] {next} -- optional
+ * (006) addx {add}
+ * (007) tax {tax}
+ * (008) ild [x+0] {ild}
+ *
+ * into this sequence:
+ *
+ * (004) nop
+ * (005) ldxms [14]
+ * (006) nop
+ * (007) nop
+ * (008) ild [x+2]
+ *
+ */
+ ild->s.k += s->s.k;
+ s->s.code = NOP;
+ add->s.code = NOP;
+ tax->s.code = NOP;
+ done = 0;
+ }
+ s = next;
+ }
+ /*
+ * If we have a subtract to do a comparsion, and the X register
+ * is a known constant, we can merge this value into the
+ * comparison.
+ */
+ if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X) &&
+ !ATOMELEM(b->out_use, A_ATOM)) {
+ val = b->val[X_ATOM];
+ if (vmap[val].is_const) {
+ b->s.k += vmap[val].const_val;
+ last->s.code = NOP;
+ done = 0;
+ } else if (b->s.k == 0) {
+ /*
+ * sub x -> nop
+ * j #0 j x
+ */
+ last->s.code = NOP;
+ b->s.code = BPF_CLASS(b->s.code) | BPF_OP(b->s.code) |
+ BPF_X;
+ done = 0;
+ }
+ }
+ /*
+ * Likewise, a constant subtract can be simplified.
+ */
+ else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K) &&
+ !ATOMELEM(b->out_use, A_ATOM)) {
+ b->s.k += last->s.k;
+ last->s.code = NOP;
+ done = 0;
+ }
+ /*
+ * and #k nop
+ * jeq #0 -> jset #k
+ */
+ if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
+ !ATOMELEM(b->out_use, A_ATOM) && b->s.k == 0) {
+ b->s.k = last->s.k;
+ b->s.code = BPF_JMP|BPF_K|BPF_JSET;
+ last->s.code = NOP;
+ done = 0;
+ opt_not(b);
+ }
+ /*
+ * If the accumulator is a known constant, we can compute the
+ * comparison result.
+ */
+ val = b->val[A_ATOM];
+ if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
+ v = vmap[val].const_val;
+ switch (BPF_OP(b->s.code)) {
+
+ case BPF_JEQ:
+ v = v == b->s.k;
+ break;
+
+ case BPF_JGT:
+ v = v > b->s.k;
+ break;
+
+ case BPF_JGE:
+ v = v >= b->s.k;
+ break;
+
+ case BPF_JSET:
+ v &= b->s.k;
+ break;
+
+ default:
+ abort();
+ }
+ if (JF(b) != JT(b))
+ done = 0;
+ if (v)
+ JF(b) = JT(b);
+ else
+ JT(b) = JF(b);
+ }
+}
+
+/*
+ * Compute the symbolic value of expression of 's', and update
+ * anything it defines in the value table 'val'. If 'alter' is true,
+ * do various optimizations. This code would be cleaner if symblic
+ * evaluation and code transformations weren't folded together.
+ */
+static void
+opt_stmt(s, val, alter)
+ struct stmt *s;
+ long val[];
+ int alter;
+{
+ int op;
+ long v;
+
+ switch (s->code) {
+
+ case BPF_LD|BPF_ABS|BPF_W:
+ case BPF_LD|BPF_ABS|BPF_H:
+ case BPF_LD|BPF_ABS|BPF_B:
+ v = F(s->code, s->k, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IND|BPF_W:
+ case BPF_LD|BPF_IND|BPF_H:
+ case BPF_LD|BPF_IND|BPF_B:
+ v = val[X_ATOM];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
+ s->k += vmap[v].const_val;
+ v = F(s->code, s->k, 0L);
+ done = 0;
+ }
+ else
+ v = F(s->code, s->k, v);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_LEN:
+ v = F(s->code, 0L, 0L);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LD|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_IMM:
+ v = K(s->k);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_LDX|BPF_MSH|BPF_B:
+ v = F(s->code, s->k, 0L);
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ALU|BPF_NEG:
+ if (alter && vmap[val[A_ATOM]].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = -vmap[val[A_ATOM]].const_val;
+ val[A_ATOM] = K(s->k);
+ }
+ else
+ val[A_ATOM] = F(s->code, val[A_ATOM], 0L);
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_K:
+ case BPF_ALU|BPF_SUB|BPF_K:
+ case BPF_ALU|BPF_MUL|BPF_K:
+ case BPF_ALU|BPF_DIV|BPF_K:
+ case BPF_ALU|BPF_AND|BPF_K:
+ case BPF_ALU|BPF_OR|BPF_K:
+ case BPF_ALU|BPF_LSH|BPF_K:
+ case BPF_ALU|BPF_RSH|BPF_K:
+ op = BPF_OP(s->code);
+ if (alter) {
+ if (s->k == 0) {
+ if (op == BPF_ADD || op == BPF_SUB ||
+ op == BPF_LSH || op == BPF_RSH ||
+ op == BPF_OR) {
+ s->code = NOP;
+ break;
+ }
+ if (op == BPF_MUL || op == BPF_AND) {
+ s->code = BPF_LD|BPF_IMM;
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ }
+ if (vmap[val[A_ATOM]].is_const) {
+ fold_op(s, val[A_ATOM], K(s->k));
+ val[A_ATOM] = K(s->k);
+ break;
+ }
+ }
+ val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
+ break;
+
+ case BPF_ALU|BPF_ADD|BPF_X:
+ case BPF_ALU|BPF_SUB|BPF_X:
+ case BPF_ALU|BPF_MUL|BPF_X:
+ case BPF_ALU|BPF_DIV|BPF_X:
+ case BPF_ALU|BPF_AND|BPF_X:
+ case BPF_ALU|BPF_OR|BPF_X:
+ case BPF_ALU|BPF_LSH|BPF_X:
+ case BPF_ALU|BPF_RSH|BPF_X:
+ op = BPF_OP(s->code);
+ if (alter && vmap[val[X_ATOM]].is_const) {
+ if (vmap[val[A_ATOM]].is_const) {
+ fold_op(s, val[A_ATOM], val[X_ATOM]);
+ val[A_ATOM] = K(s->k);
+ }
+ else {
+ s->code = BPF_ALU|BPF_K|op;
+ s->k = vmap[val[X_ATOM]].const_val;
+ done = 0;
+ val[A_ATOM] =
+ F(s->code, val[A_ATOM], K(s->k));
+ }
+ break;
+ }
+ /*
+ * Check if we're doing something to an accumulator
+ * that is 0, and simplify. This may not seem like
+ * much of a simplification but it could open up further
+ * optimizations.
+ * XXX We could also check for mul by 1, and -1, etc.
+ */
+ if (alter && vmap[val[A_ATOM]].is_const
+ && vmap[val[A_ATOM]].const_val == 0) {
+ if (op == BPF_ADD || op == BPF_OR ||
+ op == BPF_LSH || op == BPF_RSH || op == BPF_SUB) {
+ s->code = BPF_MISC|BPF_TXA;
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+ }
+ else if (op == BPF_MUL || op == BPF_DIV ||
+ op == BPF_AND) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = 0;
+ vstore(s, &val[A_ATOM], K(s->k), alter);
+ break;
+ }
+ else if (op == BPF_NEG) {
+ s->code = NOP;
+ break;
+ }
+ }
+ val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]);
+ break;
+
+ case BPF_MISC|BPF_TXA:
+ vstore(s, &val[A_ATOM], val[X_ATOM], alter);
+ break;
+
+ case BPF_LD|BPF_MEM:
+ v = val[s->k];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LD|BPF_IMM;
+ s->k = vmap[v].const_val;
+ done = 0;
+ }
+ vstore(s, &val[A_ATOM], v, alter);
+ break;
+
+ case BPF_MISC|BPF_TAX:
+ vstore(s, &val[X_ATOM], val[A_ATOM], alter);
+ break;
+
+ case BPF_LDX|BPF_MEM:
+ v = val[s->k];
+ if (alter && vmap[v].is_const) {
+ s->code = BPF_LDX|BPF_IMM;
+ s->k = vmap[v].const_val;
+ done = 0;
+ }
+ vstore(s, &val[X_ATOM], v, alter);
+ break;
+
+ case BPF_ST:
+ vstore(s, &val[s->k], val[A_ATOM], alter);
+ break;
+
+ case BPF_STX:
+ vstore(s, &val[s->k], val[X_ATOM], alter);
+ break;
+ }
+}
+
+static void
+deadstmt(s, last)
+ register struct stmt *s;
+ register struct stmt *last[];
+{
+ register int atom;
+
+ atom = atomuse(s);
+ if (atom >= 0) {
+ if (atom == AX_ATOM) {
+ last[X_ATOM] = 0;
+ last[A_ATOM] = 0;
+ }
+ else
+ last[atom] = 0;
+ }
+ atom = atomdef(s);
+ if (atom >= 0) {
+ if (last[atom]) {
+ done = 0;
+ last[atom]->code = NOP;
+ }
+ last[atom] = s;
+ }
+}
+
+static void
+opt_deadstores(b)
+ register struct block *b;
+{
+ register struct slist *s;
+ register int atom;
+ struct stmt *last[N_ATOMS];
+
+ bzero((char *)last, sizeof last);
+
+ for (s = b->stmts; s != 0; s = s->next)
+ deadstmt(&s->s, last);
+ deadstmt(&b->s, last);
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (last[atom] && !ATOMELEM(b->out_use, atom)) {
+ last[atom]->code = NOP;
+ done = 0;
+ }
+}
+
+static void
+opt_blk(b, do_stmts)
+ struct block *b;
+{
+ struct slist *s;
+ struct edge *p;
+ int i;
+ long aval;
+
+ /*
+ * Initialize the atom values.
+ * If we have no predecessors, everything is undefined.
+ * Otherwise, we inherent our values from our predecessors.
+ * If any register has an ambiguous value (i.e. control paths are
+ * merging) give it the undefined value of 0.
+ */
+ p = b->in_edges;
+ if (p == 0)
+ bzero((char *)b->val, sizeof(b->val));
+ else {
+ bcopy((char *)p->pred->val, (char *)b->val, sizeof(b->val));
+ while (p = p->next) {
+ for (i = 0; i < N_ATOMS; ++i)
+ if (b->val[i] != p->pred->val[i])
+ b->val[i] = 0;
+ }
+ }
+ aval = b->val[A_ATOM];
+ for (s = b->stmts; s; s = s->next)
+ opt_stmt(&s->s, b->val, do_stmts);
+
+ /*
+ * This is a special case: if we don't use anything from this
+ * block, and we load the accumulator with value that is
+ * already there, eliminate all the statements.
+ */
+ if (do_stmts && b->out_use == 0 && aval != 0 &&
+ b->val[A_ATOM] == aval)
+ b->stmts = 0;
+ else {
+ opt_peep(b);
+ opt_deadstores(b);
+ }
+ /*
+ * Set up values for branch optimizer.
+ */
+ if (BPF_SRC(b->s.code) == BPF_K)
+ b->oval = K(b->s.k);
+ else
+ b->oval = b->val[X_ATOM];
+ b->et.code = b->s.code;
+ b->ef.code = -b->s.code;
+}
+
+/*
+ * Return true if any register that is used on exit from 'succ', has
+ * an exit value that is different from the corresponding exit value
+ * from 'b'.
+ */
+static int
+use_conflict(b, succ)
+ struct block *b, *succ;
+{
+ int atom;
+ atomset use = succ->out_use;
+
+ if (use == 0)
+ return 0;
+
+ for (atom = 0; atom < N_ATOMS; ++atom)
+ if (ATOMELEM(use, atom))
+ if (b->val[atom] != succ->val[atom])
+ return 1;
+ return 0;
+}
+
+struct block *
+fold_edge(child, ep)
+ struct block *child;
+ struct edge *ep;
+{
+ int sense;
+ int aval0, aval1, oval0, oval1;
+ int code = ep->code;
+
+ if (code < 0) {
+ code = -code;
+ sense = 0;
+ } else
+ sense = 1;
+
+ if (child->s.code != code)
+ return 0;
+
+ aval0 = child->val[A_ATOM];
+ oval0 = child->oval;
+ aval1 = ep->pred->val[A_ATOM];
+ oval1 = ep->pred->oval;
+
+ if (aval0 != aval1)
+ return 0;
+
+ if (oval0 == oval1)
+ /*
+ * The operands are identical, so the
+ * result is true if a true branch was
+ * taken to get here, otherwise false.
+ */
+ return sense ? JT(child) : JF(child);
+
+ if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
+ /*
+ * At this point, we only know the comparison if we
+ * came down the true branch, and it was an equility
+ * comparison with a constant. We rely on the fact that
+ * distinct constants have distinct value numbers.
+ */
+ return JF(child);
+
+ return 0;
+}
+
+static void
+opt_j(ep)
+ struct edge *ep;
+{
+ register int i, k;
+ register struct block *target;
+
+ if (JT(ep->succ) == 0)
+ return;
+
+ if (JT(ep->succ) == JF(ep->succ)) {
+ /*
+ * Common branch targets can be eliminated, provided
+ * there is no data dependency.
+ */
+ if (!use_conflict(ep->pred, ep->succ->et.succ)) {
+ done = 0;
+ ep->succ = JT(ep->succ);
+ }
+ }
+ /*
+ * For each edge dominator that matches the successor of this
+ * edge, promote the edge succesor to the its grandchild.
+ *
+ * XXX We violate the set abstraction here in favor a reasonbly
+ * efficient loop.
+ */
+ top:
+ for (i = 0; i < edgewords; ++i) {
+ register u_long x = ep->edom[i];
+
+ while (x != 0) {
+ k = ffs(x) - 1;
+ x &=~ 1 << k;
+ k += i * BITS_PER_WORD;
+
+ target = fold_edge(ep->succ, edges[k]);
+ /*
+ * Check that there is no data dependency between
+ * nodes that will be violated if we move the edge.
+ */
+ if (target != 0 && !use_conflict(ep->pred, target)) {
+ done = 0;
+ ep->succ = target;
+ if (JT(target) != 0)
+ /*
+ * Start over unless we hit a leaf.
+ */
+ goto top;
+ return;
+ }
+ }
+ }
+}
+
+
+static void
+or_pullup(b)
+ struct block *b;
+{
+ int val, at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ * XXX why?
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred);
+ else
+ diffp = &JF(b->in_edges->pred);
+
+ at_top = 1;
+ while (1) {
+ if (*diffp == 0)
+ return;
+
+ if (JT(*diffp) != JT(b))
+ return;
+
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ diffp = &JF(*diffp);
+ at_top = 0;
+ }
+ samep = &JF(*diffp);
+ while (1) {
+ if (*samep == 0)
+ return;
+
+ if (JT(*samep) != JT(b))
+ return;
+
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between dp0 and dp1. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JF(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JF(pull);
+ JF(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ done = 0;
+}
+
+static void
+and_pullup(b)
+ struct block *b;
+{
+ int val, at_top;
+ struct block *pull;
+ struct block **diffp, **samep;
+ struct edge *ep;
+
+ ep = b->in_edges;
+ if (ep == 0)
+ return;
+
+ /*
+ * Make sure each predecessor loads the same value.
+ */
+ val = ep->pred->val[A_ATOM];
+ for (ep = ep->next; ep != 0; ep = ep->next)
+ if (val != ep->pred->val[A_ATOM])
+ return;
+
+ if (JT(b->in_edges->pred) == b)
+ diffp = &JT(b->in_edges->pred);
+ else
+ diffp = &JF(b->in_edges->pred);
+
+ at_top = 1;
+ while (1) {
+ if (*diffp == 0)
+ return;
+
+ if (JF(*diffp) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*diffp)->dom, b->id))
+ return;
+
+ if ((*diffp)->val[A_ATOM] != val)
+ break;
+
+ diffp = &JT(*diffp);
+ at_top = 0;
+ }
+ samep = &JT(*diffp);
+ while (1) {
+ if (*samep == 0)
+ return;
+
+ if (JF(*samep) != JF(b))
+ return;
+
+ if (!SET_MEMBER((*samep)->dom, b->id))
+ return;
+
+ if ((*samep)->val[A_ATOM] == val)
+ break;
+
+ /* XXX Need to check that there are no data dependencies
+ between diffp and samep. Currently, the code generator
+ will not produce such dependencies. */
+ samep = &JT(*samep);
+ }
+#ifdef notdef
+ /* XXX This doesn't cover everything. */
+ for (i = 0; i < N_ATOMS; ++i)
+ if ((*samep)->val[i] != pred->val[i])
+ return;
+#endif
+ /* Pull up the node. */
+ pull = *samep;
+ *samep = JT(pull);
+ JT(pull) = *diffp;
+
+ /*
+ * At the top of the chain, each predecessor needs to point at the
+ * pulled up node. Inside the chain, there is only one predecessor
+ * to worry about.
+ */
+ if (at_top) {
+ for (ep = b->in_edges; ep != 0; ep = ep->next) {
+ if (JT(ep->pred) == b)
+ JT(ep->pred) = pull;
+ else
+ JF(ep->pred) = pull;
+ }
+ }
+ else
+ *diffp = pull;
+
+ done = 0;
+}
+
+static void
+opt_blks(root, do_stmts)
+ struct block *root;
+{
+ int i, maxlevel;
+ struct block *p;
+
+ init_val();
+ maxlevel = root->level;
+ for (i = maxlevel; i >= 0; --i)
+ for (p = levels[i]; p; p = p->link)
+ opt_blk(p, do_stmts);
+
+ if (do_stmts)
+ /*
+ * No point trying to move branches; it can't possibly
+ * make a difference at this point.
+ */
+ return;
+
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ opt_j(&p->et);
+ opt_j(&p->ef);
+ }
+ }
+ for (i = 1; i <= maxlevel; ++i) {
+ for (p = levels[i]; p; p = p->link) {
+ or_pullup(p);
+ and_pullup(p);
+ }
+ }
+}
+
+static inline void
+link_inedge(parent, child)
+ struct edge *parent;
+ struct block *child;
+{
+ parent->next = child->in_edges;
+ child->in_edges = parent;
+}
+
+static void
+find_inedges(root)
+ struct block *root;
+{
+ int i;
+ struct block *b;
+ struct edge *ep;
+
+ for (i = 0; i < n_blocks; ++i)
+ blocks[i]->in_edges = 0;
+
+ /*
+ * Traverse the graph, adding each edge to the predecessor
+ * list of its sucessors. Skip the leaves (i.e. level 0).
+ */
+ for (i = root->level; i > 0; --i) {
+ for (b = levels[i]; b != 0; b = b->link) {
+ link_inedge(&b->et, JT(b));
+ link_inedge(&b->ef, JF(b));
+ }
+ }
+}
+
+static void
+opt_root(b)
+ struct block **b;
+{
+ struct slist *tmp, *s;
+
+ s = (*b)->stmts;
+ (*b)->stmts = 0;
+ while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
+ *b = JT(*b);
+
+ tmp = (*b)->stmts;
+ if (tmp != 0)
+ sappend(s, tmp);
+ (*b)->stmts = s;
+}
+
+static void
+opt_loop(root, do_stmts)
+ struct block *root;
+ int do_stmts;
+{
+ int passes = 0;
+#ifdef BDEBUG
+ if (dflag > 1)
+ opt_dump(root);
+#endif
+ do {
+ done = 1;
+ find_levels(root);
+ find_dom(root);
+ find_closure(root);
+ find_inedges(root);
+ find_ud(root);
+ find_edom(root);
+ opt_blks(root, do_stmts);
+#ifdef BDEBUG
+ if (dflag > 1)
+ opt_dump(root);
+#endif
+ } while (!done);
+}
+
+/*
+ * Optimize the filter code in its dag representation.
+ */
+void
+optimize(rootp)
+ struct block **rootp;
+{
+ struct block *root;
+
+ root = *rootp;
+
+ opt_init(root);
+ opt_loop(root, 0);
+ opt_loop(root, 1);
+ intern_blocks(root);
+ opt_root(rootp);
+ opt_cleanup();
+}
+
+static void
+make_marks(p)
+ struct block *p;
+{
+ if (!isMarked(p)) {
+ Mark(p);
+ if (BPF_CLASS(p->s.code) != BPF_RET) {
+ make_marks(JT(p));
+ make_marks(JF(p));
+ }
+ }
+}
+
+/*
+ * Mark code array such that isMarked(i) is true
+ * only for nodes that are alive.
+ */
+static void
+mark_code(p)
+ struct block *p;
+{
+ cur_mark += 1;
+ make_marks(p);
+}
+
+/*
+ * True iff the two stmt lists load the same value from the packet into
+ * the accumulator.
+ */
+static int
+eq_slist(x, y)
+ struct slist *x, *y;
+{
+ while (1) {
+ while (x && x->s.code == NOP)
+ x = x->next;
+ while (y && y->s.code == NOP)
+ y = y->next;
+ if (x == 0)
+ return y == 0;
+ if (y == 0)
+ return x == 0;
+ if (x->s.code != y->s.code || x->s.k != y->s.k)
+ return 0;
+ x = x->next;
+ y = y->next;
+ }
+}
+
+static inline int
+eq_blk(b0, b1)
+ struct block *b0, *b1;
+{
+ if (b0->s.code == b1->s.code &&
+ b0->s.k == b1->s.k &&
+ b0->et.succ == b1->et.succ &&
+ b0->ef.succ == b1->ef.succ)
+ return eq_slist(b0->stmts, b1->stmts);
+ return 0;
+}
+
+static void
+intern_blocks(root)
+ struct block *root;
+{
+ struct block *p;
+ int i, j;
+ int done;
+ top:
+ done = 1;
+ for (i = 0; i < n_blocks; ++i)
+ blocks[i]->link = 0;
+
+ mark_code(root);
+
+ for (i = n_blocks - 1; --i >= 0; ) {
+ if (!isMarked(blocks[i]))
+ continue;
+ for (j = i + 1; j < n_blocks; ++j) {
+ if (!isMarked(blocks[j]))
+ continue;
+ if (eq_blk(blocks[i], blocks[j])) {
+ blocks[i]->link = blocks[j]->link ?
+ blocks[j]->link : blocks[j];
+ break;
+ }
+ }
+ }
+ for (i = 0; i < n_blocks; ++i) {
+ p = blocks[i];
+ if (JT(p) == 0)
+ continue;
+ if (JT(p)->link) {
+ done = 0;
+ JT(p) = JT(p)->link;
+ }
+ if (JF(p)->link) {
+ done = 0;
+ JF(p) = JF(p)->link;
+ }
+ }
+ if (!done)
+ goto top;
+}
+
+static void
+opt_cleanup()
+{
+ free((void *)vnode_base);
+ free((void *)vmap);
+ free((void *)edges);
+ free((void *)space);
+ free((void *)levels);
+ free((void *)blocks);
+}
+
+/*
+ * Return the number of stmts in 's'.
+ */
+static int
+slength(s)
+ struct slist *s;
+{
+ int n = 0;
+
+ for (; s; s = s->next)
+ if (s->s.code != NOP)
+ ++n;
+ return n;
+}
+
+/*
+ * Return the number of nodes reachable by 'p'.
+ * All nodes should be initially unmarked.
+ */
+static int
+count_blocks(p)
+ struct block *p;
+{
+ if (p == 0 || isMarked(p))
+ return 0;
+ Mark(p);
+ return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;
+}
+
+/*
+ * Do a depth first search on the flow graph, numbering the
+ * the basic blocks, and entering them into the 'blocks' array.`
+ */
+static void
+number_blks_r(p)
+ struct block *p;
+{
+ int n;
+
+ if (p == 0 || isMarked(p))
+ return;
+
+ Mark(p);
+ n = n_blocks++;
+ p->id = n;
+ blocks[n] = p;
+
+ number_blks_r(JT(p));
+ number_blks_r(JF(p));
+}
+
+/*
+ * Return the number of stmts in the flowgraph reachable by 'p'.
+ * The nodes should be unmarked before calling.
+ */
+static int
+count_stmts(p)
+ struct block *p;
+{
+ int n;
+
+ if (p == 0 || isMarked(p))
+ return 0;
+ Mark(p);
+ n = count_stmts(JT(p)) + count_stmts(JF(p));
+ return slength(p->stmts) + n + 1;
+}
+
+/*
+ * Allocate memory. All allocation is done before optimization
+ * is begun. A linear bound on the size of all data structures is computed
+ * from the total number of blocks and/or statements.
+ */
+static void
+opt_init(root)
+ struct block *root;
+{
+ u_long *p;
+ int i, n, max_stmts;
+
+ /*
+ * First, count the blocks, so we can malloc an array to map
+ * block number to block. Then, put the blocks into the array.
+ */
+ unMarkAll();
+ n = count_blocks(root);
+ blocks = (struct block **)malloc(n * sizeof(*blocks));
+ unMarkAll();
+ n_blocks = 0;
+ number_blks_r(root);
+
+ n_edges = 2 * n_blocks;
+ edges = (struct edge **)malloc(n_edges * sizeof(*edges));
+
+ /*
+ * The number of levels is bounded by the number of nodes.
+ */
+ levels = (struct block **)malloc(n_blocks * sizeof(*levels));
+
+ edgewords = n_edges / (8 * sizeof(u_long)) + 1;
+ nodewords = n_blocks / (8 * sizeof(u_long)) + 1;
+
+ /* XXX */
+ space = (u_long *)malloc(2 * n_blocks * nodewords * sizeof(*space)
+ + n_edges * edgewords * sizeof(*space));
+ p = space;
+ all_dom_sets = p;
+ for (i = 0; i < n; ++i) {
+ blocks[i]->dom = p;
+ p += nodewords;
+ }
+ all_closure_sets = p;
+ for (i = 0; i < n; ++i) {
+ blocks[i]->closure = p;
+ p += nodewords;
+ }
+ all_edge_sets = p;
+ for (i = 0; i < n; ++i) {
+ register struct block *b = blocks[i];
+
+ b->et.edom = p;
+ p += edgewords;
+ b->ef.edom = p;
+ p += edgewords;
+ b->et.id = i;
+ edges[i] = &b->et;
+ b->ef.id = n_blocks + i;
+ edges[n_blocks + i] = &b->ef;
+ b->et.pred = b;
+ b->ef.pred = b;
+ }
+ max_stmts = 0;
+ for (i = 0; i < n; ++i)
+ max_stmts += slength(blocks[i]->stmts) + 1;
+ /*
+ * We allocate at most 3 value numbers per statement,
+ * so this is an upper bound on the number of valnodes
+ * we'll need.
+ */
+ maxval = 3 * max_stmts;
+ vmap = (struct vmapinfo *)malloc(maxval * sizeof(*vmap));
+ vnode_base = (struct valnode *)malloc(maxval * sizeof(*vmap));
+}
+
+/*
+ * Some pointers used to convert the basic block form of the code,
+ * into the array form that BPF requires. 'fstart' will point to
+ * the malloc'd array while 'ftail' is used during the recursive traversal.
+ */
+static struct bpf_insn *fstart;
+static struct bpf_insn *ftail;
+
+#ifdef BDEBUG
+int bids[1000];
+#endif
+
+static void
+convert_code_r(p)
+ struct block *p;
+{
+ struct bpf_insn *dst;
+ struct slist *src;
+ int slen;
+ u_int off;
+
+ if (p == 0 || isMarked(p))
+ return;
+ Mark(p);
+
+ convert_code_r(JF(p));
+ convert_code_r(JT(p));
+
+ slen = slength(p->stmts);
+ dst = ftail -= slen + 1;
+
+ p->offset = dst - fstart;
+
+ for (src = p->stmts; src; src = src->next) {
+ if (src->s.code == NOP)
+ continue;
+ dst->code = (u_short)src->s.code;
+ dst->k = src->s.k;
+ ++dst;
+ }
+#ifdef BDEBUG
+ bids[dst - fstart] = p->id + 1;
+#endif
+ dst->code = (u_short)p->s.code;
+ dst->k = p->s.k;
+ if (JT(p)) {
+ off = JT(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256)
+ error("long jumps not supported");
+ dst->jt = off;
+ off = JF(p)->offset - (p->offset + slen) - 1;
+ if (off >= 256)
+ error("long jumps not supported");
+ dst->jf = off;
+ }
+}
+
+
+/*
+ * Convert flowgraph intermediate representation to the
+ * BPF array representation. Set *lenp to the number of instructions.
+ */
+struct bpf_insn *
+icode_to_fcode(root, lenp)
+ struct block *root;
+ int *lenp;
+{
+ int n;
+ struct bpf_insn *fp;
+
+ unMarkAll();
+ n = *lenp = count_stmts(root);
+
+ fp = (struct bpf_insn *)malloc(sizeof(*fp) * n);
+ bzero((char *)fp, sizeof(*fp) * n);
+ fstart = fp;
+ ftail = fp + n;
+
+ unMarkAll();
+ convert_code_r(root);
+
+ return fp;
+}
+
+#ifdef BDEBUG
+opt_dump(root)
+ struct block *root;
+{
+ struct bpf_program f;
+
+ bzero(bids, sizeof bids);
+ f.bf_insns = icode_to_fcode(root, &f.bf_len);
+ bpf_dump(&f, 1);
+ putchar('\n');
+ free((char *)f.bf_insns);
+}
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/os.c b/usr.sbin/tcpdump/tcpdump/os.c
new file mode 100644
index 0000000..856fb5a
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/os.c
@@ -0,0 +1,26 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#) $Header: os-bsd.c,v 1.2 90/09/21 02:12:17 mccanne Exp $ (LBL)";
+#endif
+
diff --git a/usr.sbin/tcpdump/tcpdump/os.h b/usr.sbin/tcpdump/tcpdump/os.h
new file mode 100644
index 0000000..e0d01cf
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/os.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ *
+ * @(#) $Header: os-bsd.h,v 1.15 91/05/05 23:59:11 mccanne 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
+
+/*
+ * Map BSD names to SunOS names.
+ */
+#if BSD >= 199006
+#define RFS_NULL NFSPROC_NULL
+#define RFS_GETATTR NFSPROC_GETATTR
+#define RFS_SETATTR NFSPROC_SETATTR
+#define RFS_ROOT NFSPROC_ROOT
+#define RFS_LOOKUP NFSPROC_LOOKUP
+#define RFS_READLINK NFSPROC_READLINK
+#define RFS_READ NFSPROC_READ
+#define RFS_WRITECACHE NFSPROC_WRITECACHE
+#define RFS_WRITE NFSPROC_WRITE
+#define RFS_CREATE NFSPROC_CREATE
+#define RFS_REMOVE NFSPROC_REMOVE
+#define RFS_RENAME NFSPROC_RENAME
+#define RFS_LINK NFSPROC_LINK
+#define RFS_SYMLINK NFSPROC_SYMLINK
+#define RFS_MKDIR NFSPROC_MKDIR
+#define RFS_RMDIR NFSPROC_RMDIR
+#define RFS_READDIR NFSPROC_READDIR
+#define RFS_STATFS NFSPROC_STATFS
+#define RFS_NPROC NFSPROC_NPROC
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/ospf.h b/usr.sbin/tcpdump/tcpdump/ospf.h
new file mode 100644
index 0000000..e3a3a6d
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/ospf.h
@@ -0,0 +1,223 @@
+/*
+ * 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: (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_long 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_long sla_tosmetric[1]; /* may repeat */
+ } un_sla;
+
+ /* AS external links advertisements */
+ struct {
+ struct in_addr asla_mask;
+ struct aslametric {
+ u_long 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_long 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_long 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_long db_seq;
+ struct lsa_hdr db_lshdr[1]; /* may repeat */
+ } un_db;
+
+ /* Link State Request */
+ struct lsr {
+ u_long ls_type;
+ struct in_addr ls_stateid;
+ struct in_addr ls_router;
+ } un_lsr[1]; /* may repeat */
+
+ /* Link State Update */
+ struct {
+ u_long 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/tcpdump/pcap.c b/usr.sbin/tcpdump/tcpdump/pcap.c
new file mode 100644
index 0000000..04c9695
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/pcap.c
@@ -0,0 +1,209 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: pcap-bpf.c,v 1.29 92/06/02 17:57:29 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h> /* optionally get BSD define */
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if.h>
+#include <string.h>
+
+#include "interface.h"
+
+extern int errno;
+
+static void
+bpf_stats(fd)
+ int fd;
+{
+ struct bpf_stat s;
+
+ if (ioctl(fd, BIOCGSTATS, &s) < 0)
+ return;
+
+ (void)fflush(stdout);
+ (void)fprintf(stderr, "%d packets received by filter\n", s.bs_recv);
+ (void)fprintf(stderr, "%d packets dropped by kernel\n", s.bs_drop);
+}
+
+void
+readloop(cnt, if_fd, fp, printit)
+ int cnt;
+ int if_fd;
+ struct bpf_program *fp;
+ void (*printit)();
+{
+ u_char *buf;
+ u_int bufsize;
+ int cc;
+
+ if (ioctl(if_fd, BIOCGBLEN, (caddr_t)&bufsize) < 0) {
+ perror("tcpdump: BIOCGBLEN");
+ exit(1);
+ }
+ buf = (u_char *)malloc(bufsize);
+
+ if (ioctl(if_fd, BIOCSETF, (caddr_t)fp) < 0) {
+ perror("tcpdump: BIOCSETF");
+ exit(1);
+ }
+ while (1) {
+ register u_char *bp, *ep;
+
+ if ((cc = read(if_fd, (char *)buf, (int)bufsize)) < 0) {
+ /* Don't choke when we get ptraced */
+ if (errno == EINTR)
+ continue;
+#if defined(sun) && !defined(BSD)
+ /*
+ * Due to a SunOS bug, after 2^31 bytes, the kernel
+ * file offset overflows and read fails with EINVAL.
+ * The lseek() to 0 will fix things.
+ */
+ if (errno == EINVAL &&
+ (long)(tell(if_fd) + bufsize) < 0) {
+ (void)lseek(if_fd, 0, 0);
+ continue;
+ }
+#endif
+ perror("tcpdump: read");
+ exit(1);
+ }
+ /*
+ * Loop through each packet.
+ */
+#define bhp ((struct bpf_hdr *)bp)
+ bp = buf;
+ ep = bp + cc;
+ while (bp < ep) {
+ register int caplen, hdrlen;
+ if (cnt >= 0 && --cnt < 0)
+ goto out;
+ (*printit)(bp + (hdrlen = bhp->bh_hdrlen),
+ &bhp->bh_tstamp, bhp->bh_datalen,
+ caplen = bhp->bh_caplen);
+ bp += BPF_WORDALIGN(caplen + hdrlen);
+ }
+#undef bhp
+ }
+ out:
+ wrapup(if_fd);
+}
+
+wrapup(fd)
+ int fd;
+{
+ bpf_stats(fd);
+ close(fd);
+}
+
+static inline 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_RDONLY);
+ } while (fd < 0 && errno == EBUSY);
+
+ if (fd < 0) {
+ (void) fprintf(stderr, "tcpdump: ");
+ perror(device);
+ exit(-1);
+ }
+ return fd;
+}
+
+int
+initdevice(device, pflag, linktype)
+ char *device;
+ int pflag;
+ int *linktype;
+{
+ struct timeval timeout;
+ int if_fd;
+ struct ifreq ifr;
+ struct bpf_version bv;
+
+ if_fd = bpf_open();
+
+ if (ioctl(if_fd, BIOCVERSION, (caddr_t)&bv) < 0)
+ warning("kernel bpf interpreter may be out of date");
+ else if (bv.bv_major != BPF_MAJOR_VERSION ||
+ bv.bv_minor < BPF_MINOR_VERSION)
+ error("requires bpf language %d.%d or higher; kernel is %d.%d",
+ BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ bv.bv_major, bv.bv_minor);
+
+ (void)strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
+ if (ioctl(if_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
+ (void) fprintf(stderr, "tcpdump: BIOCSETIF: ");
+ perror(device);
+ exit(-1);
+ }
+ /* Get the data link layer type. */
+ if (ioctl(if_fd, BIOCGDLT, (caddr_t)linktype) < 0) {
+ perror("tcpdump: BIOCGDLT");
+ exit(-1);
+ }
+ /* set timeout */
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+ if (ioctl(if_fd, BIOCSRTIMEOUT, (caddr_t)&timeout) < 0) {
+ perror("tcpdump: BIOCSRTIMEOUT");
+ exit(-1);
+ }
+ /* set promiscuous mode if requested, but only for broadcast nets */
+ if (pflag == 0) {
+ switch (*linktype) {
+
+ case DLT_SLIP:
+ case DLT_PPP:
+ case DLT_NULL:
+ break;
+
+ default:
+ if (ioctl(if_fd, BIOCPROMISC, (void *)0) < 0) {
+ perror("tcpdump: BIOCPROMISC");
+ exit(-1);
+ }
+ }
+ }
+ return(if_fd);
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-arp.c b/usr.sbin/tcpdump/tcpdump/print-arp.c
new file mode 100644
index 0000000..3f0671a
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-arp.c
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-arp.c,v 1.16 91/04/19 10:45:56 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+arp_print(ap, length, caplen)
+ register struct ether_arp *ap;
+ int length;
+ int caplen;
+{
+ if ((u_char *)(ap + 1) > snapend) {
+ printf("[|arp]");
+ return;
+ }
+ if (length < sizeof(struct ether_arp)) {
+ (void)printf("truncated-arp");
+ default_print((u_short *)ap, length);
+ return;
+ }
+
+ NTOHS(ap->arp_hrd);
+ NTOHS(ap->arp_pro);
+ NTOHS(ap->arp_op);
+
+ if (ap->arp_hrd != ARPHRD_ETHER
+ || (ap->arp_pro != ETHERTYPE_IP
+ && ap->arp_pro != ETHERTYPE_TRAIL)
+ || ap->arp_hln != sizeof(SHA(ap))
+ || ap->arp_pln != sizeof(SPA(ap))) {
+ (void)printf("arp-req #%d for proto #%d (%d) hardware %d (%d)",
+ ap->arp_op, ap->arp_pro, ap->arp_pln,
+ ap->arp_hrd, ap->arp_hln);
+ return;
+ }
+ if (ap->arp_pro == ETHERTYPE_TRAIL)
+ (void)printf("trailer");
+ switch (ap->arp_op) {
+
+ case ARPOP_REQUEST:
+ (void)printf("arp who-has %s tell %s",
+ ipaddr_string(TPA(ap)),
+ ipaddr_string(SPA(ap)));
+ break;
+
+ case ARPOP_REPLY:
+ (void)printf("arp reply %s is-at %s",
+ ipaddr_string(SPA(ap)),
+ etheraddr_string(SHA(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", ap->arp_op);
+ default_print((u_short *)ap, caplen);
+ break;
+ }
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-atalk.c b/usr.sbin/tcpdump/tcpdump/print-atalk.c
new file mode 100644
index 0000000..203585e
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-atalk.c
@@ -0,0 +1,478 @@
+/*
+ * 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 AppleTalk packets.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#)$Header: print-atalk.c,v 1.22 92/03/26 14:15:34 mccanne Exp $ (LBL)";
+#endif
+
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <stdio.h>
+
+#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>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "appletalk.h"
+#include <strings.h>
+#include "extract.h"
+
+static char *ataddr_string();
+static struct atNBPtuple *nbp_tuple_print();
+static struct atNBPtuple *nbp_name_print();
+static void atp_print();
+static void nbp_print();
+static void atp_bitmap_print();
+
+/*
+ * Print AppleTalk Datagram Delivery Protocol packets.
+ */
+void
+ddp_print(dp, length)
+ register struct atDDP *dp;
+ int length;
+{
+ if (length < ddpSize) {
+ (void)printf(" truncated-ddp %d", length);
+ return;
+ }
+ (void)printf("%s.%d > %s.%d:",
+ ataddr_string(EXTRACT_SHORT(&dp->srcNet), dp->srcNode),
+ dp->srcSkt,
+ ataddr_string(EXTRACT_SHORT(&dp->dstNet), dp->dstNode),
+ dp->dstSkt);
+
+ /* 'type' is the last field of 'dp' so we need the whole thing.
+ If we cannot determine the type, bail out. (This last byte
+ happens to be *one* byte past the end of tcpdump's minimum
+ snapshot length.) */
+ if ((u_char *)(dp + 1) > snapend) {
+ printf(" [|atalk]");
+ return;
+ }
+
+ length -= ddpSize;
+ switch (dp->type) {
+
+ case ddpRTMP:
+ (void)printf(" at-rtmp %d", length);
+ break;
+ case ddpRTMPrequest:
+ (void)printf(" at-rtmpReq %d", length);
+ break;
+ case ddpNBP:
+ nbp_print((struct atNBP *)((u_char *)dp + ddpSize),
+ length, dp);
+ break;
+ case ddpATP:
+ atp_print((struct atATP *)((u_char *)dp + ddpSize), length);
+ break;
+ case ddpECHO:
+ (void)printf(" at-echo %d", length);
+ break;
+ case ddpIP:
+ (void)printf(" at-IP %d", length);
+ break;
+ case ddpARP:
+ (void)printf(" at-ARP %d", length);
+ break;
+ case ddpKLAP:
+ (void)printf(" at-KLAP %d", length);
+ break;
+ default:
+ (void)printf(" at-#%d %d", length);
+ break;
+ }
+}
+
+static void
+atp_print(ap, length)
+ register struct atATP *ap;
+ int length;
+{
+ char c;
+ long data;
+
+ if ((u_char *)(ap + 1) > snapend) {
+ /* Just bail if we don't have the whole chunk. */
+ printf(" [|atalk]");
+ 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(bm)
+ 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(np, length, dp)
+ register struct atNBP *np;
+ int length;
+ register struct atDDP *dp;
+{
+ register struct atNBPtuple *tp =
+ (struct atNBPtuple *)((u_char *)np + nbpHeaderSize);
+ int i = length;
+ 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 ((u_char *)tp > ep) {
+ printf(" [|atalk]");
+ return;
+ }
+ switch (i = np->control & 0xf0) {
+
+ case nbpBrRq:
+ case nbpLkUp:
+ (void)printf(i == nbpLkUp? " nbp-lkup %d:":" nbp-brRq %d:",
+ np->id);
+ if ((u_char *)(tp + 1) > ep) {
+ printf(" [|atalk]");
+ 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) != EXTRACT_SHORT(&dp->srcNet) ||
+ tp->node != dp->srcNode || tp->skt != dp->srcSkt)
+ (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, dp);
+ break;
+
+ default:
+ (void)printf(" nbp-0x%x %d (%d)", np->control, np->id,
+ length);
+ break;
+ }
+}
+
+/* print a counted string */
+static char *
+print_cstring(cp, ep)
+ register char *cp;
+ register u_char *ep;
+{
+ register int length;
+
+ if (cp >= (char *)ep) {
+ (void)printf("[|atalk]");
+ 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) {
+ (void)printf("[|atalk]");
+ return (0);
+ }
+ putchar(*cp++);
+ }
+ return (cp);
+}
+
+static struct atNBPtuple *
+nbp_tuple_print(tp, ep, dp)
+ register struct atNBPtuple *tp;
+ register u_char *ep;
+ register struct atDDP *dp;
+{
+ register struct atNBPtuple *tpn;
+
+ if ((u_char *)(tp + 1) > ep) {
+ printf(" [|atalk]");
+ 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 != dp->srcSkt)
+ (void)printf(" %d", tp->skt);
+
+ /* if the address doesn't match the src address, it's an anomaly */
+ if (EXTRACT_SHORT(&tp->net) != EXTRACT_SHORT(&dp->srcNet) ||
+ tp->node != dp->srcNode)
+ (void)printf(" [addr=%s]",
+ ataddr_string(EXTRACT_SHORT(&tp->net), tp->node));
+
+ return (tpn);
+}
+
+static struct atNBPtuple *
+nbp_name_print(tp, ep)
+ struct atNBPtuple *tp;
+ register u_char *ep;
+{
+ register char *cp = (char *)tp + nbpTupleSize;
+
+ putchar(' ');
+
+ /* Object */
+ putchar('"');
+ if (cp = print_cstring(cp, ep)) {
+ /* Type */
+ putchar(':');
+ if (cp = print_cstring(cp, ep)) {
+ /* Zone */
+ putchar('@');
+ if (cp = print_cstring(cp, ep))
+ putchar('"');
+ }
+ }
+ return ((struct atNBPtuple *)cp);
+}
+
+
+#define HASHNAMESIZE 4096
+
+struct hnamemem {
+ int addr;
+ char *name;
+ struct hnamemem *nxt;
+};
+
+static struct hnamemem hnametable[HASHNAMESIZE];
+
+static char *
+ataddr_string(atnet, athost)
+ 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));
+ i3 = strlen(nambuf) + 1;
+ tp->name = strcpy(malloc((unsigned) i3), 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);
+ i = strlen(nambuf) + 1;
+ tp->name = strcpy(malloc((unsigned) i), 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((unsigned) i), nambuf);
+
+ return (tp->name);
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-bootp.c b/usr.sbin/tcpdump/tcpdump/print-bootp.c
new file mode 100644
index 0000000..0641d82
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-bootp.c
@@ -0,0 +1,263 @@
+/*
+ * 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.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-bootp.c,v 1.17 91/11/14 22:21:34 leres Exp $ (LBL)";
+#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 <netinet/if_ether.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "bootp.h"
+
+void rfc1048_print();
+void cmu_print();
+
+/*
+ * Print bootp requests
+ */
+void
+bootp_print(bp, length, sport, dport)
+ register 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;
+
+#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);
+ }
+
+ NTOHL(bp->bp_xid);
+ NTOHS(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", bp->bp_xid);
+ if (bp->bp_secs)
+ printf(" secs:%d", 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 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) != 0)
+ printf(" ether %s", etheraddr_string(bp->bp_chaddr));
+ }
+
+ 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;
+
+ TCHECK(bp->bp_vend[0], sizeof(bp->bp_vend));
+ printf(" vend");
+ if (bcmp(bp->bp_vend, vm_rfc1048, sizeof(u_long)) == 0)
+ rfc1048_print(bp->bp_vend, sizeof(bp->bp_vend));
+ else if (bcmp(bp->bp_vend, vm_cmu, sizeof(u_long)) == 0)
+ cmu_print(bp->bp_vend, sizeof(bp->bp_vend));
+ else {
+ u_long ul;
+
+ bcopy((char *)bp->bp_vend, (char *)&ul, sizeof(ul));
+ printf("-#0x%x", ul);
+ }
+
+ return;
+trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
+
+void
+rfc1048_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ u_char tag;
+ u_char *ep;
+ register int i;
+ u_long ul;
+
+ printf("-rfc1048");
+
+ /* Step over magic cookie */
+ bp += sizeof(long);
+
+ /* Setup end pointer */
+ ep = bp + length;
+
+ while (bp < ep) {
+ tag = *bp++;
+ i = *bp++;
+ switch (tag) {
+
+ case TAG_PAD:
+ /* no-op */
+ break;
+
+ case TAG_SUBNET_MASK:
+ ul = 0;
+ bcopy((char *)bp, (char *)&ul, i);
+ printf(" SM:%s", ipaddr_string(&ul));
+ break;
+
+ case TAG_TIME_SERVER:
+ ul = 0;
+ bcopy((char *)bp, (char *)&ul, i);
+ printf(" TS:%s", ipaddr_string(&ul));
+ break;
+
+ case TAG_GATEWAY:
+ ul = 0;
+ bcopy((char *)bp, (char *)&ul, i);
+ printf(" G:%s", ipaddr_string(&ul));
+ break;
+
+ case TAG_TIME_OFFSET:
+ case TAG_NAME_SERVER:
+ case TAG_DOMAIN_SERVER:
+ case TAG_LOG_SERVER:
+ case TAG_COOKIE_SERVER:
+ case TAG_LPR_SERVER:
+ case TAG_IMPRESS_SERVER:
+ case TAG_RLP_SERVER:
+ case TAG_HOSTNAME:
+ case TAG_BOOTSIZE:
+ printf(" tag-#%d", tag);
+ if (i == sizeof(long)) {
+ bcopy((char *)bp, (char *)&ul, sizeof(long));
+ printf(":0x%x", ul);
+ } else
+ printf(":?");
+ break;
+
+ case TAG_END:
+ return;
+
+ default:
+ printf("[tag-#%d]", tag);
+ return;
+ }
+ }
+}
+
+void
+cmu_print(bp, length)
+ register u_char *bp;
+ int length;
+{
+ /* XXX not really implemented */
+ printf("-cmu [...]");
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-domain.c b/usr.sbin/tcpdump/tcpdump/print-domain.c
new file mode 100644
index 0000000..04cf5aa
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-domain.c
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-domain.c,v 1.16 92/05/25 14:28:59 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.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 <arpa/nameser.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 u_char *
+ns_nskip(cp)
+ register 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(cp, bp, ep)
+ register u_char *cp;
+ register u_char *bp;
+ register u_char *ep;
+{
+ register u_int i;
+
+ putchar(' ');
+ if (i = *cp++)
+ 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('.');
+}
+
+
+/* print a query */
+static void
+ns_qprint(cp, bp, ep)
+ register u_char *cp;
+ register u_char *bp;
+ register u_char *ep;
+{
+ 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;
+ switch (i |= *cp++) {
+ case T_A: printf(" A"); break;
+ case T_NS: printf(" NS"); break;
+ case T_MD: printf(" MD"); break;
+ case T_MF: printf(" MF"); break;
+ case T_CNAME: printf(" CNAME"); break;
+ case T_SOA: printf(" SOA"); break;
+ case T_MB: printf(" MB"); break;
+ case T_MG: printf(" MG"); break;
+ case T_MR: printf(" MR"); break;
+ case T_NULL: printf(" NULL"); break;
+ case T_WKS: printf(" WKS"); break;
+ case T_PTR: printf(" PTR"); break;
+ case T_HINFO: printf(" HINFO"); break;
+ case T_MINFO: printf(" MINFO"); break;
+ case T_MX: printf(" MX"); break;
+ case T_UINFO: printf(" UINFO"); break;
+ case T_UID: printf(" UID"); break;
+ case T_GID: printf(" GID"); break;
+#ifdef T_UNSPEC
+ case T_UNSPEC: printf(" UNSPEC"); break;
+#endif
+ case T_AXFR: printf(" AXFR"); break;
+ case T_MAILB: printf(" MAILB"); break;
+ case T_MAILA: printf(" MAILA"); break;
+ case T_ANY: printf(" ANY"); break;
+ default: printf(" Type%d", i); break;
+ }
+ 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(cp, bp, ep)
+ register u_char *cp;
+ register u_char *bp;
+ register 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;
+ switch (typ) {
+ case T_A: printf(" A %s", ipaddr_string(cp)); break;
+ case T_NS: printf(" NS"); ns_nprint(cp, bp, ep); break;
+ case T_MD: printf(" MD"); break;
+ case T_MF: printf(" MF"); break;
+ case T_CNAME: printf(" CNAME"); ns_nprint(cp, bp, ep); break;
+ case T_SOA: printf(" SOA"); break;
+ case T_MB: printf(" MB"); break;
+ case T_MG: printf(" MG"); break;
+ case T_MR: printf(" MR"); break;
+ case T_NULL: printf(" NULL"); break;
+ case T_WKS: printf(" WKS"); break;
+ case T_PTR: printf(" PTR"); ns_nprint(cp, bp, ep); break;
+ case T_HINFO: printf(" HINFO"); break;
+ case T_MINFO: printf(" MINFO"); break;
+ case T_MX: printf(" 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;
+ case T_UINFO: printf(" UINFO"); break;
+ case T_UID: printf(" UID"); break;
+ case T_GID: printf(" GID"); break;
+#ifdef T_UNSPEC
+ case T_UNSPEC: printf(" UNSPEC"); break;
+#endif
+ case T_AXFR: printf(" AXFR"); break;
+ case T_MAILB: printf(" MAILB"); break;
+ case T_MAILA: printf(" MAILA"); break;
+ case T_ANY: printf(" ANY"); break;
+ default: printf(" Type%d", typ); break;
+ }
+}
+
+void
+ns_print(np, length)
+ register HEADER *np;
+ int length;
+{
+ u_char *ep = (u_char *)snapend;
+
+ /* get the byte-order right */
+ NTOHS(np->id);
+ NTOHS(np->qdcount);
+ NTOHS(np->ancount);
+ NTOHS(np->nscount);
+ NTOHS(np->arcount);
+
+ if (np->qr) {
+ /* this is a response */
+ printf(" %d%s%s%s%s%s",
+ np->id,
+ ns_ops[np->opcode],
+ ns_resp[np->rcode],
+ np->aa? "*" : "",
+ np->ra? "" : "-",
+ np->tc? "|" : "");
+ if (np->qdcount != 1)
+ printf(" [%dq]", np->qdcount);
+ printf(" %d/%d/%d", np->ancount, np->nscount, np->arcount);
+ if (np->ancount)
+ ns_rprint(ns_nskip((u_char *)(np + 1)) + 4,
+ (u_char *)np, ep);
+ }
+ else {
+ /* this is a request */
+ printf(" %d%s%s",
+ 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 (np->qdcount)
+ printf(" [%dq]", np->qdcount);
+ if (np->ancount != 1)
+ printf(" [%da]", np->ancount);
+ }
+ else {
+ if (np->ancount)
+ printf(" [%da]", np->ancount);
+ if (np->qdcount != 1)
+ printf(" [%dq]", np->qdcount);
+ }
+ if (np->nscount)
+ printf(" [%dn]", np->nscount);
+ if (np->arcount)
+ printf(" [%dau]", np->arcount);
+
+ ns_qprint((u_char *)(np + 1), (u_char *)np, ep);
+ }
+ printf(" (%d)", length);
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-egp.c b/usr.sbin/tcpdump/tcpdump/print-egp.c
new file mode 100644
index 0000000..a88a683
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-egp.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1991 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).
+ */
+#include <stdio.h>
+#include <sys/param.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 "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_long 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(egp, length)
+ register struct egp_packet *egp;
+ register int length;
+{
+ register u_char *cp, *ep;
+#define TCHECK(n) if (cp > ep - n) goto trunc
+ register u_long addr;
+ register u_long 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_long)*cp++ << 24;
+ if (IN_CLASSB(addr)) {
+ TCHECK(1);
+ addr |= (u_long)*cp++ << 16;
+ } else if (!IN_CLASSA(addr)) {
+ TCHECK(2);
+ addr |= (u_long)*cp++ << 16;
+ addr |= (u_long)*cp++ << 8;
+ }
+ printf(" %s", intoa(addr));
+ }
+ }
+ putchar(')');
+ }
+ return;
+trunc:
+ fputs("[|]", stdout);
+}
+
+void
+egp_print(egp, length, ip)
+ register struct egp_packet *egp;
+ register int length;
+ register struct ip *ip;
+{
+ register int status;
+ register int code;
+ register int type;
+
+ (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(" unsolicitied");
+ }
+ 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]", status);
+
+ if (ntohs(egp->egp_reason) <= EGPR_UVERSION)
+ printf(" %s", egp_reasons[ntohs(egp->egp_reason)]);
+ else
+ printf(" [reason]", ntohs(egp->egp_reason));
+ break;
+
+ default:
+ printf("[type %d]", type);
+ break;
+ }
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-ether.c b/usr.sbin/tcpdump/tcpdump/print-ether.c
new file mode 100644
index 0000000..2d01c17
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-ether.c
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-ether.c,v 1.22 91/10/07 20:18:28 leres Exp $ (LBL)";
+#endif
+
+#include <sys/param.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 "interface.h"
+#include "addrtoname.h"
+
+u_char *packetp;
+u_char *snapend;
+
+static inline void
+ether_print(ep, length)
+ register struct ether_header *ep;
+ int length;
+{
+ 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(p, tvp, length, caplen)
+ u_char *p;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct ether_header *ep;
+ register int i;
+
+ ts_print(tvp);
+
+ if (caplen < sizeof(struct ether_header)) {
+ printf("[|ether]");
+ goto out;
+ }
+
+ if (eflag)
+ ether_print((struct ether_header *)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);
+ ep = (struct ether_header *)p;
+ p += sizeof(struct ether_header);
+ switch (ntohs(ep->ether_type)) {
+
+ case ETHERTYPE_IP:
+ ip_print((struct ip *)p, length);
+ break;
+
+ case ETHERTYPE_ARP:
+ case ETHERTYPE_REVARP:
+ arp_print((struct ether_arp *)p, length, caplen - sizeof(*ep));
+ break;
+
+ default:
+ if (!eflag)
+ ether_print(ep, length);
+ if (!xflag && !qflag)
+ default_print((u_short *)p, caplen - sizeof(*ep));
+ break;
+ }
+ if (xflag)
+ default_print((u_short *)p, caplen - sizeof(*ep));
+ out:
+ putchar('\n');
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-fddi.c b/usr.sbin/tcpdump/tcpdump/print-fddi.c
new file mode 100644
index 0000000..7783112
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-fddi.c
@@ -0,0 +1,236 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: print-fddi.c,v 1.4 92/02/03 16:04:02 van Exp $ (LBL)";
+#endif
+
+#ifdef FDDI
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.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 <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/*
+ * 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
+ */
+
+/* XXX This goes somewhere else. */
+#define FDDI_HDRLEN 21
+
+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,
+};
+
+static inline void
+fddi_print(p, length)
+ u_char *p;
+ int length;
+{
+ u_char fsrc[6], fdst[6];
+ register char *srcname, *dstname;
+ register int i;
+
+ /*
+ * bit-swap the fddi addresses (isn't the IEEE standards
+ * process wonderful!) then convert them to names.
+ */
+
+ for (i = 0; i < sizeof(fdst); ++i)
+ fdst[i] = fddi_bit_swap[p[i+1]];
+ for (i = 0; i < sizeof(fsrc); ++i)
+ fsrc[i] = fddi_bit_swap[p[i+7]];
+ dstname = etheraddr_string(fdst);
+ srcname = etheraddr_string(fsrc);
+
+ if (vflag)
+ printf("%s %s %02x %02x %02x %02x %02x%02x%02x %s %d: ",
+ dstname, srcname,
+ p[0],
+ p[13], p[14], p[15],
+ p[16], p[17], p[18],
+ etherproto_string((p[19] << 8) | p[20]),
+ length);
+ else if (qflag)
+ printf("%s %s %d: ", dstname, srcname, length);
+ else
+ printf("%s %s %02x %s %d: ",
+ dstname, srcname,
+ p[0],
+ etherproto_string((p[19] << 8) | p[20]),
+ length);
+}
+
+void
+fddi_if_print(p, tvp, length, caplen)
+ u_char *p;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct ip *ip;
+ u_short type;
+
+ ts_print(tvp);
+
+ if (caplen < FDDI_HDRLEN) {
+ printf("[|fddi]");
+ 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 = (u_char *)p;
+ snapend = (u_char *)p + caplen;
+
+ /*
+ * If the frame is not an LLC frame or is not an LLC/UI frame
+ * or doesn't have SNAP as a dest NSAP, use the default printer.
+ * (XXX - should interpret SMT packets here.)
+ */
+ if ((p[0] & 0xf8) != 0x50)
+ /* not LLC frame -- use default printer */
+ type = 0;
+ else if ((p[15] &~ 0x10) != 0x03)
+ /* not UI frame -- use default printer */
+ type = 0;
+ else if (p[13] != 170)
+ /* DSAP not SNAP -- use default printer */
+ type = 0;
+ else
+ type = (p[19] << 8) | p[20];
+ if (eflag)
+ fddi_print(p, length);
+
+ length -= FDDI_HDRLEN;
+ p += FDDI_HDRLEN;
+
+ switch (ntohs(type)) {
+
+ case ETHERTYPE_IP:
+ ip_print((struct ip *)p, length);
+ break;
+
+ case ETHERTYPE_ARP:
+ case ETHERTYPE_REVARP:
+ arp_print((struct ether_arp *)p, length, caplen - FDDI_HDRLEN);
+ break;
+
+ default:
+ if (!eflag)
+ fddi_print(p, length);
+ if (!xflag && !qflag)
+ default_print((u_short *)p, caplen - FDDI_HDRLEN);
+ break;
+ }
+ if (xflag)
+ default_print((u_short *)p, caplen - sizeof(FDDI_HDRLEN));
+out:
+ putchar('\n');
+}
+#else
+#include <stdio.h>
+void
+fddi_if_print()
+{
+ void error();
+
+ error("not configured for fddi");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/print-icmp.c b/usr.sbin/tcpdump/tcpdump/print-icmp.c
new file mode 100644
index 0000000..928d866
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-icmp.c
@@ -0,0 +1,207 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-icmp.c,v 1.11 91/03/27 17:42:58 leres Exp $ (LBL)";
+#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 <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 <netinet/ip_icmp.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+void
+icmp_print(dp, ip)
+ register struct icmp *dp;
+ register struct ip *ip;
+{
+ char buf[256];
+ register char *str = buf;
+ register struct ip *oip;
+ register struct udphdr *ouh;
+ register int hlen;
+ u_char *ep;
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *)snapend;
+
+ (void)printf("%s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ strcpy(str, "[?]");
+
+ 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);
+ 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(ouh->uh_dport));
+ break;
+ case IPPROTO_UDP:
+ (void)sprintf(buf,
+ "%s udp port %s unreachable",
+ ipaddr_string(&oip->ip_dst),
+ udpport_string(ouh->uh_dport));
+ break;
+ default:
+ (void)sprintf(buf,
+ "%s protocol %d port %d unreachable",
+ ipaddr_string(&oip->ip_dst),
+ oip->ip_p, ouh->uh_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", dp->icmp_mask);
+ break;
+ }
+ (void)printf("icmp: %s", str);
+ return;
+trunc:
+ fputs("[|icmp]", stdout);
+#undef TCHECK
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-ip.c b/usr.sbin/tcpdump/tcpdump/print-ip.c
new file mode 100644
index 0000000..85c2ad9
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-ip.c
@@ -0,0 +1,393 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: /home/ncvs/src/usr.sbin/tcpdump/tcpdump/print-ip.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+#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>
+#include <netinet/igmp.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "dvmrp.h" /* in mrouted directory */
+
+void
+igmp_print(cp, len, ip)
+ register u_char *cp;
+ register int len;
+ register struct ip *ip;
+{
+ register u_char *ep = (u_char *)snapend;
+ struct igmp *igmp = (struct igmp *)cp;
+
+ (void)printf("%s > %s: ",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+
+ if (cp + 7 > ep) {
+ (void)printf("[|igmp]");
+ return;
+ }
+ switch (igmp->igmp_type) {
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ (void)printf("igmp query");
+ if (igmp->igmp_group.s_addr)
+ (void)printf(" [gaddr %s]",
+ ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ (void)printf("igmp report %s", ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+ case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
+ printf("igmp new report %s", ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+
+ case IGMP_HOST_LEAVE_MESSAGE:
+ printf("igmp leave %s", ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+
+ case IGMP_DVMRP:
+ (void)printf("igmp dvmrp");
+ switch(igmp->igmp_code) {
+ case DVMRP_PROBE:
+ printf(" probe");
+ break;
+ case DVMRP_REPORT:
+ printf(" report");
+ break;
+ case DVMRP_ASK_NEIGHBORS:
+ printf(" neighbor list request");
+ break;
+ case DVMRP_NEIGHBORS:
+ printf(" neighbor list reply");
+ break;
+ case DVMRP_ASK_NEIGHBORS2:
+ printf(" neighbor list request v2");
+ break;
+ case DVMRP_NEIGHBORS2:
+ printf(" neighbor list reply v2");
+ break;
+ case DVMRP_PRUNE:
+ printf(" prune");
+ break;
+ case DVMRP_GRAFT:
+ printf(" graft");
+ break;
+ case DVMRP_GRAFT_ACK:
+ printf(" graft ack");
+ break;
+ default:
+ printf("-%d", igmp->igmp_code);
+ break;
+ }
+
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+ case IGMP_MTRACE:
+ (void)printf("igmp traceroute %s",
+ ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+ case IGMP_MTRACE_RESP:
+ (void)printf("igmp traceroute resp %s",
+ ipaddr_string(&igmp->igmp_group));
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ if (len != IGMP_MINLEN)
+ (void)printf(" [len %d]", len);
+ break;
+ default:
+ (void)printf("igmp-%x", igmp->igmp_type);
+ if (igmp->igmp_code)
+ printf(" [code %d]", igmp->igmp_code);
+ break;
+ }
+}
+
+/*
+ * print the recorded route in an IP RR, LSRR or SSRR option.
+ */
+static void
+ip_printroute(type, cp, length)
+ char *type;
+ register 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(cp, length)
+ register 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;
+ }
+ }
+}
+
+/*
+ * print an IP datagram.
+ */
+void
+ip_print(ip, length)
+ register struct ip *ip;
+ register int length;
+{
+ register int hlen;
+ register int len;
+ register unsigned char *cp;
+
+#ifdef TCPDUMP_ALIGN
+ static u_char *abuf;
+ /*
+ * 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 ((int)ip & (sizeof(long)-1)) {
+ 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;
+ if (hlen < sizeof (struct ip)) {
+ printf("invalid ip header length %d", hlen);
+ return;
+ }
+
+ if (ip->ip_v != 4) {
+ printf("unknown ip version %d", ip->ip_v);
+ return;
+ }
+
+ NTOHS(ip->ip_len);
+ NTOHS(ip->ip_off);
+ NTOHS(ip->ip_id);
+
+ len = ip->ip_len - hlen;
+ if (length < ip->ip_len)
+ (void)printf("truncated-ip - %d bytes missing!",
+ ip->ip_len - length);
+
+ /*
+ * If this is fragment zero, hand it to the next higher
+ * level protocol.
+ */
+ if ((ip->ip_off & 0x1fff) == 0) {
+ cp = (unsigned char *)ip + hlen;
+ switch (ip->ip_p) {
+
+ case IPPROTO_TCP:
+ tcp_print((struct tcphdr *)cp, len, ip);
+ break;
+ case IPPROTO_UDP:
+ udp_print((struct udphdr *)cp, len, ip);
+ break;
+ case IPPROTO_ICMP:
+ icmp_print((struct icmp *)cp, 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((struct egp_packet *)cp, len, ip);
+ break;
+#ifndef IPPROTO_OSPF
+#define IPPROTO_OSPF 89
+#endif
+ case IPPROTO_OSPF:
+ ospf_print((struct ospfhdr *)cp, len, ip);
+ break;
+#ifndef IPPROTO_IGMP
+#define IPPROTO_IGMP 2
+#endif
+ case IPPROTO_IGMP:
+ igmp_print(cp, len, ip);
+ 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 (ip->ip_off & 0x3fff) {
+ /*
+ * if this isn't the first frag, we're missing the
+ * next level protocol header. print the ip addr.
+ */
+ if (ip->ip_off & 0x1fff)
+ (void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst));
+ (void)printf(" (frag %d:%d@%d%s)", ip->ip_id, len,
+ (ip->ip_off & 0x1fff) * 8,
+ (ip->ip_off & IP_MF)? "+" : "");
+ } else if (ip->ip_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) {
+ char *sep = "";
+
+ printf(" (");
+ if (ip->ip_ttl > 1) {
+ (void)printf("%sttl %d", sep, (int)ip->ip_ttl);
+ sep = ", ";
+ }
+ if ((ip->ip_off & 0x3fff) == 0) {
+ (void)printf("%sid %d", sep, (int)ip->ip_id);
+ 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/tcpdump/print-nfs.c b/usr.sbin/tcpdump/tcpdump/print-nfs.c
new file mode 100644
index 0000000..593e334
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-nfs.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 1990, 1991, 1992 The Regents 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: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-nfs.c,v 1.1.1.1 1993/06/12 14:42:08 rgrimes Exp $ (LBL)";
+#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 <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <sys/time.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+
+#include <ctype.h>
+
+#include "interface.h"
+/* These must come after interface.h for BSD. */
+#if BSD >= 199006
+#include <sys/ucred.h>
+#include <nfs/nfsv2.h>
+#endif
+#include <nfs/nfs.h>
+
+#include "addrtoname.h"
+#include "extract.h"
+
+static void nfs_printfh();
+static void nfs_printfn();
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Byte swap an array of n words.
+ * Assume input is word-aligned.
+ * Check that buffer is bounded by "snapend".
+ */
+static void
+bswap(bp, n)
+ register u_long *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
+
+void
+nfsreply_print(rp, length, ip)
+ register struct rpc_msg *rp;
+ int length;
+ register struct ip *ip;
+{
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+ if (!nflag)
+ (void)printf("%s.nfs > %s.%x: reply %s %d",
+ ipaddr_string(&ip->ip_src),
+ ipaddr_string(&ip->ip_dst),
+ rp->rm_xid,
+ 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),
+ rp->rm_xid,
+ rp->rm_reply.rp_stat == MSG_ACCEPTED? "ok":"ERR",
+ length);
+}
+
+/*
+ * Return a pointer to the first file handle in the packet.
+ * If the packet was truncated, return 0.
+ */
+static u_long *
+parsereq(rp, length)
+ register struct rpc_msg *rp;
+ register int length;
+{
+ register u_long *dp = (u_long *)&rp->rm_call.cb_cred;
+ register u_long *ep = (u_long *)snapend;
+
+ /*
+ * find the start of the req data (if we captured it)
+ * note that dp[1] was already byte swapped by bswap()
+ */
+ if (dp < ep && dp[1] < length) {
+ dp += (dp[1] + (2*sizeof(u_long) + 3)) / sizeof(u_long);
+ if ((dp < ep) && (dp[1] < length)) {
+ dp += (dp[1] + (2*sizeof(u_long) + 3)) /
+ sizeof(u_long);
+ 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 u_long *
+parsefh(dp)
+ register u_long *dp;
+{
+ if (dp + 8 <= (u_long *)snapend) {
+ nfs_printfh(dp);
+ return (dp + 8);
+ }
+ return (0);
+}
+
+/*
+ * Print out a file name and return pointer to longword past it.
+ * If packet was truncated, return 0.
+ */
+static u_long *
+parsefn(dp)
+ register u_long *dp;
+{
+ register int len;
+ register 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 long pointer (NFS filenames are padded to long) */
+ dp += ((len + 3) & ~3) / sizeof(*dp);
+ if ((u_char *)dp > snapend)
+ return (0);
+ nfs_printfn(cp, len);
+
+ return (dp);
+}
+
+/*
+ * Print out file handle and file name.
+ * Return pointer to longword past file name.
+ * If packet was truncated (or there was some other error), return 0.
+ */
+static u_long *
+parsefhn(dp)
+ register u_long *dp;
+{
+ dp = parsefh(dp);
+ if (dp == 0)
+ return (0);
+ putchar(' ');
+ return (parsefn(dp));
+}
+
+void
+nfsreq_print(rp, length, ip)
+ register struct rpc_msg *rp;
+ int length;
+ register struct ip *ip;
+{
+ register u_long *dp;
+ register u_char *ep = snapend;
+#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+
+ if (!nflag)
+ (void)printf("%s.%x > %s.nfs: %d",
+ ipaddr_string(&ip->ip_src),
+ rp->rm_xid,
+ ipaddr_string(&ip->ip_dst),
+ length);
+ else
+ (void)printf("%s.%x > %s.%x: %d",
+ ipaddr_string(&ip->ip_src),
+ rp->rm_xid,
+ ipaddr_string(&ip->ip_dst),
+ NFS_PORT,
+ length);
+
+ switch (rp->rm_call.cb_proc) {
+#ifdef NFSPROC_NOOP
+ case NFSPROC_NOOP:
+ printf(" nop");
+ return;
+#else
+#define NFSPROC_NOOP -1
+#endif
+ case RFS_NULL:
+ printf(" null");
+ return;
+
+ case RFS_GETATTR:
+ printf(" getattr");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ case RFS_SETATTR:
+ printf(" setattr");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+#if RFS_ROOT != NFSPROC_NOOP
+ case RFS_ROOT:
+ printf(" root");
+ break;
+#endif
+ case RFS_LOOKUP:
+ printf(" lookup");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case RFS_READLINK:
+ printf(" readlink");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ case RFS_READ:
+ printf(" read");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 3 * sizeof(*dp));
+ printf(" %lu (%lu) bytes @ %lu",
+ ntohl(dp[1]), ntohl(dp[2]), ntohl(dp[0]));
+ return;
+ }
+ break;
+
+#if RFS_WRITECACHE != NFSPROC_NOOP
+ case RFS_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 RFS_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 RFS_CREATE:
+ printf(" create");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case RFS_REMOVE:
+ printf(" remove");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case RFS_RENAME:
+ printf(" rename");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefhn(dp)) != 0) {
+ fputs(" ->", stdout);
+ if (parsefhn(dp) != 0)
+ return;
+ }
+ break;
+
+ case RFS_LINK:
+ printf(" link");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ fputs(" ->", stdout);
+ if (parsefhn(dp) != 0)
+ return;
+ }
+ break;
+
+ case RFS_SYMLINK:
+ printf(" symlink");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefhn(dp)) != 0) {
+ fputs(" -> ", stdout);
+ if (parsefn(dp) != 0)
+ return;
+ }
+ break;
+
+ case RFS_MKDIR:
+ printf(" mkdir");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case RFS_RMDIR:
+ printf(" rmdir");
+ if ((dp = parsereq(rp, length)) != 0 && parsefhn(dp) != 0)
+ return;
+ break;
+
+ case RFS_READDIR:
+ printf(" readdir");
+ if ((dp = parsereq(rp, length)) != 0 &&
+ (dp = parsefh(dp)) != 0) {
+ TCHECK(dp, 2 * sizeof(*dp));
+ printf(" %lu bytes @ %lu", ntohl(dp[1]), ntohl(dp[0]));
+ return;
+ }
+ break;
+
+ case RFS_STATFS:
+ printf(" statfs");
+ if ((dp = parsereq(rp, length)) != 0 && parsefh(dp) != 0)
+ return;
+ break;
+
+ default:
+ printf(" proc-%lu", 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.
+ */
+static void
+nfs_printfh(dp)
+ register u_long *dp;
+{
+ /*
+ * take a wild guess at the structure of file handles.
+ * On sun 3s, there are 2 longs of fsid, a short
+ * len == 8, a long of inode & a long of generation number.
+ * On sun 4s, the len == 10 & there are 2 bytes of
+ * padding immediately following it.
+ */
+ if (dp[2] == 0xa0000) {
+ if (dp[1])
+ (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1], dp[3]);
+ else
+ (void) printf(" fh %ld.%ld", dp[0], dp[3]);
+ } else if ((dp[2] >> 16) == 8)
+ /*
+ * 'dp' is longword aligned, so we must use the extract
+ * macros below for dp+10 which cannot possibly be aligned.
+ */
+ if (dp[1])
+ (void) printf(" fh %ld.%ld.%lu", dp[0], dp[1],
+ EXTRACT_LONG((u_char *)dp + 10));
+ else
+ (void) printf(" fh %ld.%ld", dp[0],
+ EXTRACT_LONG((u_char *)dp + 10));
+ /* On Ultrix pre-4.0, three longs: fsid, fno, fgen and then zeros */
+ else if (dp[3] == 0) {
+ (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
+ dp[1], dp[2]);
+ }
+ /*
+ * On Ultrix 4.0,
+ * five longs: fsid, fno, fgen, eno, egen and then zeros
+ */
+ else if (dp[5] == 0) {
+ (void)printf(" fh %d,%d/%ld.%ld", major(dp[0]), minor(dp[0]),
+ dp[1], dp[2]);
+ if (vflag) {
+ /* print additional info */
+ (void)printf("[%ld.%ld]", dp[3], dp[4]);
+ }
+ }
+ else
+ (void) printf(" fh %lu.%lu.%lu.%lu",
+ dp[0], dp[1], dp[2], dp[3]);
+}
+
+/*
+ * Print out an NFS filename.
+ * Assumes that len bytes from cp are present in packet.
+ */
+static void
+nfs_printfn(cp, len)
+ register u_char *cp;
+ register int len;
+{
+ register char c;
+
+ /* Sanity */
+ if (len >= 64) {
+ fputs("[\">]", stdout);
+ return;
+ }
+ /* Print out the filename */
+ putchar('"');
+ while (--len >= 0) {
+ c = toascii(*cp++);
+ if (!isascii(c)) {
+ c = toascii(c);
+ putchar('M');
+ putchar('-');
+ }
+ if (!isprint(c)) {
+ c ^= 0x40; /* DEL to ?, others to alpha */
+ putchar('^');
+ }
+ putchar(c);
+ }
+ putchar('"');
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-ntp.c b/usr.sbin/tcpdump/tcpdump/print-ntp.c
new file mode 100644
index 0000000..86f6ba7
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-ntp.c
@@ -0,0 +1,277 @@
+/*
+ * 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 ntp packets.
+ * By Jeffrey Mogul/DECWRL
+ * loosely based on print-bootp.c
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-ntp.c,v 1.7 92/01/04 01:45:16 leres Exp $ (LBL)";
+#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 <netinet/if_ether.h>
+#include <strings.h>
+#include <ctype.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+#include "ntp.h"
+
+/*
+ * Print ntp requests
+ */
+void
+ntp_print(bp, length)
+ register struct ntpdata *bp;
+ int length;
+{
+ u_char *ep;
+ int mode, version, leapind;
+ static char rclock[5];
+
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+
+ /* Note funny sized packets */
+ if (length != sizeof(struct ntpdata))
+ (void)printf(" [len=%d]", length);
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *)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
+}
+
+p_sfix(sfp)
+ register 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 */
+
+p_ntp_time(lfp)
+ register struct l_fixedpt *lfp;
+{
+ register long i;
+ register unsigned long uf;
+ register unsigned long 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 */
+p_ntp_delta(olfp, lfp)
+ register struct l_fixedpt *olfp;
+ register struct l_fixedpt *lfp;
+{
+ register long i;
+ register unsigned long uf;
+ register unsigned long ouf;
+ register unsigned long 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/tcpdump/print-null.c b/usr.sbin/tcpdump/tcpdump/print-null.c
new file mode 100644
index 0000000..b186068
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-null.c
@@ -0,0 +1,117 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: print-null.c,v 1.3 91/10/07 20:19:11 leres Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.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 <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#define NULL_HDRLEN 4
+
+static void
+null_print(p, ip, length)
+ u_char *p;
+ 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(p, tvp, length, caplen)
+ u_char *p;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct ip *ip;
+
+ ts_print(tvp);
+
+ /*
+ * 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 = (u_char *)p;
+ snapend = (u_char *)p + caplen;
+
+ length -= NULL_HDRLEN;
+
+ ip = (struct ip *)(p + NULL_HDRLEN);
+
+ if (eflag)
+ null_print(p, ip, length);
+
+ ip_print(ip, length);
+
+ if (xflag)
+ default_print((u_short *)ip, caplen - NULL_HDRLEN);
+ putchar('\n');
+}
+
diff --git a/usr.sbin/tcpdump/tcpdump/print-ospf.c b/usr.sbin/tcpdump/tcpdump/print-ospf.c
new file mode 100644
index 0000000..90daf94
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-ospf.c
@@ -0,0 +1,586 @@
+/*
+ * 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: (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.1 92/01/29 12:44:17 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.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 "ospf.h"
+#include "interface.h"
+#include "addrtoname.h"
+
+#ifndef __GNUC__
+#define inline
+#endif
+
+#if !defined(__STDC__) && !defined(const)
+#define const
+#endif /* !defined(__STDC__) && !defined(const) */
+
+struct bits {
+ u_long bit;
+ const char *str;
+};
+
+static const struct bits ospf_option_bits[] = {
+ OSPF_OPTION_T, "T",
+ OSPF_OPTION_E, "E",
+ OSPF_OPTION_MC, "MC",
+ 0, (char *) 0
+};
+
+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, (char *) 0
+};
+
+static const char *ospf_types[OSPF_TYPE_MAX] = {
+ (char *) 0,
+ "hello",
+ "dd",
+ "ls_req",
+ "ls_upd",
+ "ls_ack"
+};
+
+static inline void
+ospf_print_seqage(seq, us)
+register u_long 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(bp, options)
+register 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(lshp, end)
+register struct lsa_hdr *lshp;
+caddr_t end;
+{
+ if ((caddr_t) (lshp + 1) > end) {
+ return 1;
+ }
+
+ printf(" {");
+
+ if (!lshp->ls_type || lshp->ls_type >= LS_TYPE_MAX) {
+ printf(" ??LS type %d?? }",
+ 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(lsap, end)
+register struct lsa *lsap;
+caddr_t end;
+{
+ register caddr_t ls_end;
+ struct rlalink *rlp;
+ struct tos_metric *tosp;
+ struct in_addr *ap;
+ struct aslametric *almp;
+ struct mcla *mcp;
+ u_long *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(" }");
+ 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(" {");
+
+ 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?? }",
+ 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(" }");
+ 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_long 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_long 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(" }");
+ return 0;
+}
+
+
+void
+ospf_print(dat, length, ip)
+u_char *dat;
+int length;
+struct ip *ip;
+{
+ register struct ospfhdr *op = (struct ospfhdr *) dat;
+ register caddr_t end = (caddr_t)snapend;
+ register struct lsa *lsap;
+ register struct lsa_hdr *lshp;
+ char sep;
+ int i, j;
+ struct in_addr *ap;
+ struct lsr *lsrp;
+
+ /* 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(" }");
+ lshp++;
+ }
+ }
+ break;
+
+ case OSPF_TYPE_LSR:
+ if (vflag) {
+ for (lsrp = op->ospf_lsr; (caddr_t) (lsrp+1) <= end; lsrp++) {
+ long type;
+
+ if ((caddr_t) (lsrp + 1) > end) {
+ break;
+ }
+
+ printf(" {");
+ if (!(type = lsrp->ls_type) || type >= LS_TYPE_MAX) {
+ printf(" ??LinkStateType %d }",
+ type);
+ printf(" }");
+ break;
+ }
+
+ LS_PRINT(lsrp, type);
+ printf(" }");
+ }
+ }
+ 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(" }");
+ 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 - dat) < length) {
+ printf(" [|]");
+ }
+
+ return; /* from ospf_print */
+}
+
+
diff --git a/usr.sbin/tcpdump/tcpdump/print-ppp.c b/usr.sbin/tcpdump/tcpdump/print-ppp.c
new file mode 100644
index 0000000..c83cc7d
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-ppp.c
@@ -0,0 +1,102 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: print-ppp.c,v 1.7 91/10/07 20:18:33 leres Exp $ (LBL)";
+#endif
+
+#ifdef PPP
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.h>
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+/* XXX This goes somewhere else. */
+#define PPP_HDRLEN 4
+
+void
+ppp_if_print(p, tvp, length, caplen)
+ u_char *p;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct ip *ip;
+
+ ts_print(tvp);
+
+ 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 = (u_char *)p;
+ snapend = (u_char *)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(ip, length);
+
+ if (xflag)
+ default_print((u_short *)ip, caplen - PPP_HDRLEN);
+out:
+ putchar('\n');
+}
+#else
+#include <stdio.h>
+void
+ppp_if_print()
+{
+ void error();
+
+ error("not configured for ppp");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/print-rip.c b/usr.sbin/tcpdump/tcpdump/print-rip.c
new file mode 100644
index 0000000..4e06594
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-rip.c
@@ -0,0 +1,142 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-rip.c,v 1.2 1994/02/10 09:17:57 davidg Exp $ (LBL)";
+#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 <errno.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+#define RIPVERSION 1
+
+struct netinfo {
+ struct osockaddr rip_dst; /* destination net/host */
+ int rip_metric; /* cost of route */
+};
+
+struct rip {
+ u_char rip_cmd; /* request/response */
+ u_char rip_vers; /* protocol version # */
+ u_char rip_res1[2]; /* pad to 32-bit boundary */
+ union {
+ struct netinfo ru_nets[1]; /* variable length... */
+ char ru_tracefile[1]; /* ditto ... */
+ } ripun;
+#define rip_nets ripun.ru_nets
+#define rip_tracefile ripun.ru_tracefile
+};
+
+/*
+ * Packet types.
+ */
+#define RIPCMD_REQUEST 1 /* want info */
+#define RIPCMD_RESPONSE 2 /* responding to request */
+#define RIPCMD_TRACEON 3 /* turn tracing on */
+#define RIPCMD_TRACEOFF 4 /* turn it off */
+
+static void
+rip_entry_print(ni)
+ register struct netinfo *ni;
+{
+ if (ntohs(ni->rip_dst.sa_family) != AF_INET) {
+ register int i;
+
+ printf(" [family %d:", ntohs(ni->rip_dst.sa_family));
+ for (i = 0; i < 14; i += 2)
+ printf(" %02x%02x", (u_char)ni->rip_dst.sa_data[i],
+ (u_char)ni->rip_dst.sa_data[i+1]);
+ printf("]");
+ } else {
+ register struct sockaddr_in *sin =
+ (struct sockaddr_in *)&ni->rip_dst;
+ printf(" %s", ipaddr_string(&sin->sin_addr));
+ if (sin->sin_port)
+ printf(" [port %d]", sin->sin_port);
+ }
+ printf("(%d)", ntohl(ni->rip_metric));
+}
+
+void
+rip_print(dat, length)
+ u_char *dat;
+ int length;
+{
+ register struct rip *rp = (struct rip *)dat;
+ register struct netinfo *ni;
+ register int amt = (u_char *)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 != RIPVERSION)
+ printf(" [vers %d]", rp->rip_vers);
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-sl.c b/usr.sbin/tcpdump/tcpdump/print-sl.c
new file mode 100644
index 0000000..2c89b42
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-sl.c
@@ -0,0 +1,246 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: print-sl.c,v 1.17 91/10/07 20:18:35 leres Exp $ (LBL)";
+#endif
+
+#ifdef CSLIP
+#include <stdio.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/socket.h>
+#include <sys/file.h>
+#include <sys/mbuf.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 <net/slcompress.h>
+#include <net/slip.h>
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "addrtoname.h"
+
+static int lastlen[2][256];
+static int lastconn = 255;
+
+static void compressed_sl_print();
+
+void
+sl_if_print(p, tvp, length, caplen)
+ u_char *p;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct ip *ip;
+
+ ts_print(tvp);
+
+ 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 = (u_char *)p;
+ snapend = (u_char *)p + caplen;
+
+ length -= SLIP_HDRLEN;
+
+ ip = (struct ip *)(p + SLIP_HDRLEN);
+
+ if (eflag)
+ sliplink_print(p, ip, length);
+
+ ip_print(ip, length);
+
+ if (xflag)
+ default_print((u_short *)ip, caplen - SLIP_HDRLEN);
+ out:
+ putchar('\n');
+}
+
+sliplink_print(p, ip, length)
+ u_char *p;
+ struct ip *ip;
+ 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 u_char *
+print_sl_change(str, cp)
+ char *str;
+ register 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 u_char *
+print_sl_winchange(cp)
+ register 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(chdr, ip, length, dir)
+ u_char *chdr;
+ int length;
+ struct ip *ip;
+ int dir;
+{
+ register 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 longs).
+ * '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 *)&((long *)ip)[hlen])->th_off;
+ lastlen[dir][lastconn] = length - (hlen << 2);
+ printf(" %d (%d)", lastlen[dir][lastconn], cp - chdr);
+}
+#else
+#include <stdio.h>
+void
+sl_if_print()
+{
+ void error();
+
+ error("not configured for slip");
+ /* NOTREACHED */
+}
+#endif
diff --git a/usr.sbin/tcpdump/tcpdump/print-snmp.c b/usr.sbin/tcpdump/tcpdump/print-snmp.c
new file mode 100644
index 0000000..d1996c0
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-snmp.c
@@ -0,0 +1,1043 @@
+/*
+ * 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.
+ *
+ * This implementaion 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 implemention 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/types.h>
+#include <stdio.h>
+#include <ctype.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 particluar, 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 abreviated 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); \
+ } \
+ 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 {
+ unsigned long asnlen;
+ union {
+ caddr_t raw;
+ long integer;
+ unsigned long uns;
+ unsigned char *str;
+ } data;
+ unsigned 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".
+ */
+int
+asn1_parse(p, len, elem)
+ register u_char *p;
+ int len;
+ struct be *elem;
+{
+ unsigned char form, class, id;
+ int indent=0, i, hdr;
+ char *classstr;
+
+ 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 unsigned 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.
+ */
+void
+asn1_print(elem)
+ 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 (!memcmp(a->oid, 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;
+ 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)printfn(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.
+ */
+void
+asn1_decode(p, length)
+ 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
+ */
+void
+varbind_print (pduid, np, length, error)
+ u_char pduid, *np;
+ int length, error;
+{
+ struct be elem;
+ int count = 0, index;
+
+ /* 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 (index = 1; length > 0; index++) {
+ u_char *vbend;
+ int vblength;
+
+ if (!error || index == 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 || index == 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 && index == error && elem.type != BE_NULL)
+ fputs("[err objVal!=NULL]", stdout);
+ if (!error || index == error)
+ asn1_print(&elem);
+
+ length = vblength;
+ np = vbend;
+ }
+}
+
+/*
+ * Decode SNMP PDUs: GetRequest, GetNextRequest, GetResponse, and SetRequest
+ */
+void
+snmppdu_print (pduid, np, length)
+ u_char pduid, *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
+ */
+void
+trap_print (np, length)
+ 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 (np, length)
+ 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(elem.data.str, DEF_COMMUNITY, sizeof(DEF_COMMUNITY)-1))
+ /* ! "public" */
+ printf("C=%.*s ", 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/tcpdump/print-sunrpc.c b/usr.sbin/tcpdump/tcpdump/print-sunrpc.c
new file mode 100644
index 0000000..e7e74be
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-sunrpc.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 1992 The Regents 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: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-sunrpc.c,v 1.1.1.1 1993/06/12 14:42:07 rgrimes Exp $ (LBL)";
+#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 <netinet/if_ether.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_var.h>
+
+#include <sys/time.h>
+#include <errno.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+
+#include <ctype.h>
+
+#include "interface.h"
+
+#include "addrtoname.h"
+#include "extract.h"
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+/*
+ * Byte swap an array of n words.
+ * Assume input is word-aligned.
+ * Check that buffer is bounded by "snapend".
+ */
+static void
+bswap(bp, n)
+ register u_long *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
+
+void
+sunrpcrequest_print(rp, length, ip)
+ register struct rpc_msg *rp;
+ int length;
+ register struct ip *ip;
+{
+ register u_long *dp;
+ register u_char *ep = snapend;
+#define TCHECK(p, l) if ((u_char *)(p) > ep - l) break
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ bswap((u_long *)rp, sizeof(*rp) / sizeof(u_long));
+#endif
+
+ if (!nflag)
+ (void)printf("%s.%x > %s.sunrpc: %d",
+ ipaddr_string(&ip->ip_src),
+ rp->rm_xid,
+ ipaddr_string(&ip->ip_dst),
+ length);
+ else
+ (void)printf("%s.%x > %s.%x: %d",
+ ipaddr_string(&ip->ip_src),
+ rp->rm_xid,
+ ipaddr_string(&ip->ip_dst),
+ PMAPPORT,
+ length);
+
+ switch (rp->rm_call.cb_proc) {
+
+ case PMAPPROC_NULL:
+ printf(" null");
+ break;
+
+ case PMAPPROC_SET:
+ printf(" set");
+ break;
+
+ case PMAPPROC_UNSET:
+ printf(" unset");
+ break;
+
+ case PMAPPROC_GETPORT:
+ printf(" getport");
+ break;
+
+ case PMAPPROC_DUMP:
+ printf(" dump");
+ break;
+
+ case PMAPPROC_CALLIT:
+ printf(" callit");
+ break;
+
+ default:
+ printf(" proc #%d", rp->rm_call.cb_proc);
+ }
+ printf(" prog #%d", rp->rm_call.cb_prog);
+ putchar('\n');
+}
+
diff --git a/usr.sbin/tcpdump/tcpdump/print-tcp.c b/usr.sbin/tcpdump/tcpdump/print-tcp.c
new file mode 100644
index 0000000..9974b3c
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-tcp.c
@@ -0,0 +1,287 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-tcp.c,v 1.18 92/05/25 14:29:04 mccanne Exp $ (LBL)";
+#endif
+
+#include <sys/param.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>
+
+#ifdef X10
+#include <X/X.h>
+#include <X/Xproto.h>
+#endif
+
+#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
+
+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(tp, length, ip)
+ register struct tcphdr *tp;
+ register int length;
+ register struct ip *ip;
+{
+ register u_char flags;
+ register int hlen;
+
+ if ((u_char *)(tp + 1) > snapend) {
+ printf("[|tcp]");
+ return;
+ }
+ if (length < sizeof(struct tcphdr)) {
+ (void)printf("truncated-tcp %d", length);
+ return;
+ }
+
+ NTOHS(tp->th_sport);
+ NTOHS(tp->th_dport);
+ NTOHL(tp->th_seq);
+ NTOHL(tp->th_ack);
+ NTOHS(tp->th_win);
+ NTOHS(tp->th_urp);
+
+ (void)printf("%s.%s > %s.%s: ",
+ ipaddr_string(&ip->ip_src), tcpport_string(tp->th_sport),
+ ipaddr_string(&ip->ip_dst), tcpport_string(tp->th_dport));
+
+ if (!qflag) {
+#ifdef X10
+ register int be;
+
+ if ((be = (tp->th_sport == X_TCP_BI_PORT ||
+ tp->th_dport == X_TCP_BI_PORT)) ||
+ tp->th_sport == X_TCP_LI_PORT ||
+ tp->th_dport == X_TCP_LI_PORT) {
+ register XReq *xp = (XReq *)(tp + 1);
+
+ x10_print(xp, length - sizeof(struct tcphdr), be);
+ return;
+ }
+#endif
+ }
+
+ 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 (tp->th_sport < tp->th_dport ||
+ (tp->th_sport == tp->th_dport &&
+ ip->ip_src.s_addr < ip->ip_dst.s_addr)) {
+ tha.src = ip->ip_src, tha.dst = ip->ip_dst;
+ tha.port = tp->th_sport << 16 | tp->th_dport;
+ rev = 0;
+ } else {
+ tha.src = ip->ip_dst, tha.dst = ip->ip_src;
+ tha.port = tp->th_dport << 16 | tp->th_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 = tp->th_seq, th->seq = tp->th_ack - 1;
+ else
+ th->seq = tp->th_seq, th->ack = tp->th_ack - 1;
+ } else {
+ if (rev)
+ tp->th_seq -= th->ack, tp->th_ack -= th->seq;
+ else
+ tp->th_seq -= th->seq, tp->th_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)", tp->th_seq, tp->th_seq + length,
+ length);
+ if (flags & TH_ACK)
+ (void)printf(" ack %lu", tp->th_ack);
+
+ (void)printf(" win %d", tp->th_win);
+
+ if (flags & TH_URG)
+ (void)printf(" urg %d", tp->th_urp);
+ /*
+ * Handle any options.
+ */
+ if ((hlen -= sizeof(struct tcphdr)) > 0) {
+ register u_char *cp = (u_char *)tp + sizeof(struct tcphdr);
+ int i;
+ char ch = '<';
+
+ putchar(' ');
+ while (--hlen >= 0) {
+ putchar(ch);
+ switch (*cp++) {
+ case TCPOPT_MAXSEG:
+ {
+ u_short mss;
+#ifdef TCPDUMP_ALIGN
+ bcopy((char *)cp + 1, (char *)&mss,
+ sizeof(mss));
+#else
+ mss = *(u_short *)(cp + 1);
+#endif
+ (void)printf("mss %d", ntohs(mss));
+ 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:
+ {
+ u_long v;
+#ifdef TCPDUMP_ALIGN
+ bcopy((char *)cp + 1, (char *)&v,
+ sizeof(v));
+#else
+ v = *(u_long *)(cp + 1);
+#endif
+ (void)printf("echo %lu", v);
+ if (*cp != 6)
+ (void)printf("[len %d]", *cp);
+ cp += 5;
+ hlen -= 5;
+ break;
+ }
+ case TCPOPT_ECHOREPLY:
+ {
+ u_long v;
+#ifdef TCPDUMP_ALIGN
+ bcopy((char *)cp + 1, (char *)&v,
+ sizeof(v));
+#else
+ v = *(u_long *)(cp + 1);
+#endif
+ (void)printf("echoreply %lu", v);
+ if (*cp != 6)
+ (void)printf("[len %d]", *cp);
+ cp += 5;
+ hlen -= 5;
+ 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/tcpdump/print-tftp.c b/usr.sbin/tcpdump/tcpdump/print-tftp.c
new file mode 100644
index 0000000..3f8f079
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-tftp.c
@@ -0,0 +1,149 @@
+/*
+ * 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 trivial file transfer protocol packets.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: print-tftp.c,v 1.13 91/04/19 10:46:57 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <arpa/tftp.h>
+
+#include "interface.h"
+#include <strings.h>
+#include <ctype.h>
+
+struct int2str {
+ int code;
+ char *str;
+};
+
+/* op code to string mapping */
+static struct int2str op2str[] = {
+ RRQ, "RRQ", /* read request */
+ WRQ, "WRQ", /* write request */
+ DATA, "DATA", /* data packet */
+ ACK, "ACK", /* acknowledgement */
+ ERROR, "ERROR", /* error code */
+ 0, 0
+};
+
+/* error code to string mapping */
+static struct int2str 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, 0
+};
+
+/*
+ * Print trivial file transfer program requests
+ */
+void
+tftp_print(tp, length)
+ register struct tftphdr *tp;
+ int length;
+{
+ register struct int2str *ts;
+ register u_char *ep;
+#define TCHECK(var, l) if ((u_char *)&(var) > ep - l) goto trunc
+ static char tstr[] = " [|tftp]";
+
+ /* 'ep' points to the end of avaible data. */
+ ep = (u_char *)snapend;
+
+ /* Print length */
+ printf(" %d", length);
+
+ /* Print tftp request type */
+ TCHECK(tp->th_opcode, sizeof(tp->th_opcode));
+ NTOHS(tp->th_opcode);
+ putchar(' ');
+ for (ts = op2str; ts->str; ++ts)
+ if (ts->code == tp->th_opcode) {
+ fputs(ts->str, stdout);
+ break;
+ }
+ if (ts->str == 0) {
+ /* Bail if bogus opcode */
+ printf("tftp-#%d", tp->th_opcode);
+ return;
+ }
+
+ switch (tp->th_opcode) {
+
+ case RRQ:
+ case WRQ:
+ putchar(' ');
+ if (printfn((u_char *)tp->th_stuff, ep)) {
+ fputs(&tstr[1], stdout);
+ return;
+ }
+ break;
+
+ case DATA:
+ TCHECK(tp->th_block, sizeof(tp->th_block));
+ NTOHS(tp->th_block);
+ printf(" block %d", tp->th_block);
+ break;
+
+ case ACK:
+ break;
+
+ case ERROR:
+ /* Print error code string */
+ TCHECK(tp->th_code, sizeof(tp->th_code));
+ NTOHS(tp->th_code);
+ putchar(' ');
+ for (ts = err2str; ts->str; ++ts)
+ if (ts->code == tp->th_code) {
+ fputs(ts->str, stdout);
+ break;
+ }
+ if (ts->str == 0)
+ printf("tftp-err-#%d", tp->th_code);
+
+ /* Print error message string */
+ putchar(' ');
+ if (printfn((u_char *)tp->th_data, ep)) {
+ fputs(&tstr[1], stdout);
+ return;
+ }
+ break;
+
+ default:
+ /* We shouldn't get here */
+ printf("(unknown #%d)", tp->th_opcode);
+ break;
+ }
+ return;
+trunc:
+ fputs(tstr, stdout);
+#undef TCHECK
+}
diff --git a/usr.sbin/tcpdump/tcpdump/print-udp.c b/usr.sbin/tcpdump/tcpdump/print-udp.c
new file mode 100644
index 0000000..14c22da
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/print-udp.c
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: /a/cvs/386BSD/src/contrib/tcpdump/tcpdump/print-udp.c,v 1.1.1.1 1993/06/12 14:42:06 rgrimes Exp $ (LBL)";
+#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 <arpa/nameser.h>
+#include <arpa/tftp.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <rpc/rpc.h>
+
+#include "interface.h"
+/* These must come after interface.h for BSD. */
+#if BSD >= 199006
+#include <sys/ucred.h>
+#include <nfs/nfsv2.h>
+#endif
+#include <nfs/nfs.h>
+
+#include "addrtoname.h"
+#include "appletalk.h"
+
+#include "bootp.h"
+
+/* 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(up, length, ip)
+ register struct udphdr *up;
+ int length;
+ register struct ip *ip;
+{
+ register u_char *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);
+
+ NTOHS(up->uh_sport);
+ NTOHS(up->uh_dport);
+ NTOHS(up->uh_ulen);
+
+ 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 (up->uh_dport == NFS_PORT && direction == CALL) {
+ nfsreq_print(rp, length, ip);
+ return;
+ }
+ else if (up->uh_sport == NFS_PORT && direction == REPLY) {
+ nfsreply_print(rp, length, ip);
+ return;
+ }
+#ifdef notdef
+ else if (up->uh_dport == SUNRPC_PORT && direction == CALL) {
+ sunrpcrequest_print(rp, length, ip);
+ return;
+ }
+#endif
+ else if (cp[2] == 2 && (atalk_port(up->uh_sport) ||
+ atalk_port(up->uh_dport))) {
+ ddp_print((struct atDDP *)(&cp[3]), length - 3);
+ return;
+ }
+ }
+ (void)printf("%s.%s > %s.%s:",
+ ipaddr_string(&ip->ip_src), udpport_string(up->uh_sport),
+ ipaddr_string(&ip->ip_dst), udpport_string(up->uh_dport));
+
+ if (!qflag) {
+#define ISPORT(p) (up->uh_dport == (p) || up->uh_sport == (p))
+ if (ISPORT(NAMESERVER_PORT))
+ ns_print((HEADER *)(up + 1), length);
+ else if (ISPORT(TFTP_PORT))
+ tftp_print((struct tftphdr *)(up + 1), length);
+ else if (ISPORT(IPPORT_BOOTPC) || ISPORT(IPPORT_BOOTPS))
+ bootp_print((struct bootp *)(up + 1), length,
+ up->uh_sport, up->uh_dport);
+ else if (up->uh_dport == RIP_PORT)
+ rip_print((u_char *)(up + 1), length);
+ else if (ISPORT(SNMP_PORT) || ISPORT(SNMPTRAP_PORT))
+ snmp_print((u_char *)(up + 1), length);
+ else if (ISPORT(NTP_PORT))
+ ntp_print((struct ntpdata *)(up + 1), length);
+ else
+ (void)printf(" udp %d", up->uh_ulen - sizeof(*up));
+#undef ISPORT
+ } else
+ (void)printf(" udp %d", up->uh_ulen - sizeof(*up));
+}
diff --git a/usr.sbin/tcpdump/tcpdump/savefile.c b/usr.sbin/tcpdump/tcpdump/savefile.c
new file mode 100644
index 0000000..79bb9e8
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/savefile.c
@@ -0,0 +1,303 @@
+/*
+ * 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: (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: savefile.c,v 1.27 92/01/26 21:29:26 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * savefile.c - supports offline use of tcpdump
+ * Extraction/creation by Jeffrey Mogul, DECWRL
+ * Modified by Steve McCanne, LBL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ * The first record in the file contains saved values for the machine
+ * dependent values so we can print the dump file on any architecture.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "version.h"
+#include "savefile.h"
+
+#define TCPDUMP_MAGIC 0xa1b2c3d4
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are longs so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ */
+struct file_header {
+ u_long magic;
+ u_short version_major;
+ u_short version_minor;
+ long thiszone; /* gmt to local correction */
+ u_long sigfigs; /* accuracy of timestamps */
+ u_long snaplen; /* max length saved portion of each pkt */
+ u_long linktype;
+};
+
+int sf_swapped;
+
+FILE *sf_readfile;
+FILE *sf_writefile;
+
+static int
+sf_write_header(fp, linktype, thiszone, snaplen, precision)
+ FILE *fp;
+ int linktype;
+ int thiszone;
+ int snaplen;
+ int precision;
+{
+ struct file_header hdr;
+
+ hdr.magic = TCPDUMP_MAGIC;
+ hdr.version_major = VERSION_MAJOR;
+ hdr.version_minor = VERSION_MINOR;
+
+ hdr.thiszone = thiszone;
+ hdr.snaplen = snaplen;
+ hdr.sigfigs = precision;
+ hdr.linktype = linktype;
+
+ if (fwrite((char *)&hdr, sizeof(hdr), 1, fp) != 1)
+ return -1;
+
+ return 0;
+}
+
+static void
+swap_hdr(hp)
+ struct file_header *hp;
+{
+ hp->version_major = SWAPSHORT(hp->version_major);
+ hp->version_minor = SWAPSHORT(hp->version_minor);
+ hp->thiszone = SWAPLONG(hp->thiszone);
+ hp->sigfigs = SWAPLONG(hp->sigfigs);
+ hp->snaplen = SWAPLONG(hp->snaplen);
+ hp->linktype = SWAPLONG(hp->linktype);
+}
+
+int
+sf_read_init(fname, linktypep, thiszonep, snaplenp, precision)
+ char *fname;
+ int *linktypep, *thiszonep, *snaplenp, *precision;
+{
+ register FILE *fp;
+ struct file_header hdr;
+
+ if (fname[0] == '-' && fname[1] == '\0')
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (fp == 0) {
+ (void) fprintf(stderr, "tcpdump: fopen: ");
+ perror(fname);
+ exit(1);
+ }
+ }
+ if (fread((char *)&hdr, sizeof(hdr), 1, fp) != 1) {
+ (void) fprintf(stderr, "tcpdump: fread: ");
+ perror(fname);
+ exit(1);
+ }
+ if (hdr.magic != TCPDUMP_MAGIC) {
+ if (SWAPLONG(hdr.magic) != TCPDUMP_MAGIC)
+ return SFERR_BADF;
+ sf_swapped = 1;
+ swap_hdr(&hdr);
+ }
+ if (hdr.version_major < VERSION_MAJOR)
+ return SFERR_BADVERSION;
+
+ *thiszonep = hdr.thiszone;
+ *snaplenp = hdr.snaplen;
+ *linktypep = hdr.linktype;
+ *precision = hdr.sigfigs;
+
+ sf_readfile = fp;
+
+ return 0;
+}
+
+/*
+ * Print out packets stored in the file initilized by sf_read_init().
+ * If cnt >= 0, return after 'cnt' packets, otherwise continue until eof.
+ */
+int
+sf_read(filtp, cnt, snaplen, printit)
+ struct bpf_program *filtp;
+ int cnt, snaplen;
+ void (*printit)();
+{
+ struct packet_header h;
+ u_char *buf;
+ struct bpf_insn *fcode = filtp->bf_insns;
+ int status = 0;
+
+ buf = (u_char *)malloc(snaplen);
+
+ while (status == 0) {
+ status = sf_next_packet(&h, buf, snaplen);
+
+ if (status)
+ break;
+ /*
+ * XXX It's possible (and likely) for us to screw up the
+ * network layer alignment when we pass down packets from
+ * this point (ip_print deals by copying the ip header
+ * to an aligned buffer). There doesn't seem to be a
+ * clean way to fix this. We could compute an offset
+ * from the link type (which would have to be passed in),
+ * but that only works for fixed size headers.
+ */
+ if (bpf_filter(fcode, buf, h.len, h.caplen)) {
+ if (cnt >= 0 && --cnt < 0)
+ break;
+ (*printit)(buf, &h.ts, h.len, h.caplen);
+ }
+ }
+
+ if (status == SFERR_EOF)
+ /* treat EOF's as okay status */
+ status = 0;
+
+ free((char *)buf);
+ return status;
+}
+
+/*
+ * Read sf_readfile and return the next packet. Return the header in hdr
+ * and the contents in buf. Return 0 on success, SFERR_EOF if there were
+ * no more packets, and SFERR_TRUNC if a partial packet was encountered.
+ */
+int
+sf_next_packet(hdr, buf, buflen)
+ struct packet_header *hdr;
+ u_char *buf;
+ int buflen;
+{
+ FILE *fp = sf_readfile;
+
+ /* read the stamp */
+ if (fread((char *)hdr, sizeof(struct packet_header), 1, fp) != 1) {
+ /* probably an EOF, though could be a truncated packet */
+ return SFERR_EOF;
+ }
+
+ if (sf_swapped) {
+ /* these were written in opposite byte order */
+ hdr->caplen = SWAPLONG(hdr->caplen);
+ hdr->len = SWAPLONG(hdr->len);
+ hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
+ hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
+ }
+
+ if (hdr->caplen > buflen)
+ return SFERR_BADF;
+
+ /* read the packet itself */
+
+ if (fread((char *)buf, hdr->caplen, 1, fp) != 1)
+ return SFERR_TRUNC;
+
+ return 0;
+}
+
+/*
+ * Initialize so that sf_write() will output to the file named 'fname'.
+ */
+void
+sf_write_init(fname, linktype, thiszone, snaplen, precision)
+ char *fname;
+ int linktype;
+ int thiszone;
+ int snaplen;
+ int precision;
+{
+ if (fname[0] == '-' && fname[1] == '\0')
+ sf_writefile = stdout;
+ else {
+ sf_writefile = fopen(fname, "w");
+ if (sf_writefile == 0) {
+ (void) fprintf(stderr, "tcpdump: fopen: ");
+ perror(fname);
+ exit(1);
+ }
+ }
+ (void)sf_write_header(sf_writefile,
+ linktype, thiszone, snaplen, precision);
+}
+
+/*
+ * Output a packet to the intialized dump file.
+ */
+void
+sf_write(sp, tvp, length, caplen)
+ u_char *sp;
+ struct timeval *tvp;
+ int length;
+ int caplen;
+{
+ struct packet_header h;
+
+ h.ts.tv_sec = tvp->tv_sec;
+ h.ts.tv_usec = tvp->tv_usec;
+ h.len = length;
+ h.caplen = caplen;
+
+ (void)fwrite((char *)&h, sizeof h, 1, sf_writefile);
+ (void)fwrite((char *)sp, caplen, 1, sf_writefile);
+}
+
+void
+sf_err(code)
+ int code;
+{
+ switch (code) {
+ case SFERR_BADVERSION:
+ error("archaic file format");
+ /* NOTREACHED */
+
+ case SFERR_BADF:
+ error("bad dump file format");
+ /* NOTREACHED */
+
+ case SFERR_TRUNC:
+ error("truncated dump file");
+ /* NOTREACHED */
+
+ case SFERR_EOF:
+ error("EOF reading dump file");
+ /* NOTREACHED */
+
+ default:
+ error("unknown dump file error code in sf_err()");
+ /* NOTREACHED */
+ }
+ abort();
+}
diff --git a/usr.sbin/tcpdump/tcpdump/savefile.h b/usr.sbin/tcpdump/tcpdump/savefile.h
new file mode 100644
index 0000000..a5082f9
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/savefile.h
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ *
+ * $Header: savefile.h,v 1.10 90/12/17 13:48:58 mccanne Exp $
+ *
+ * Header for offline storage info.
+ * Extraction/creation by Jeffrey Mogul, DECWRL.
+ *
+ * Used to save the received packet headers, after filtering, to
+ * a file, and then read them later.
+ */
+
+/*
+ * Each packet in the dump file is prepended with this generic header.
+ * This gets around the problem of different headers for different
+ * packet interfaces.
+ */
+struct packet_header {
+ struct timeval ts; /* time stamp */
+ u_long len; /* length this packet (off wire) */
+ u_long caplen; /* length of portion present */
+};
+
+/* true if the contents of the savefile being read are byte-swapped */
+extern int sf_swapped;
+
+/* macros for when sf_swapped is true: */
+/*
+ * We use the "receiver-makes-right" approach to byte order,
+ * because time is at a premium when we are writing the file.
+ * In other words, the file_header and packet_header records
+ * are written in host byte order.
+ * Note that the packets are always written in network byte order.
+ *
+ * ntoh[ls] aren't sufficient because we might need to swap on a big-endian
+ * machine (if the file was written in little-end order).
+ */
+#define SWAPLONG(y) \
+((((y)&0xff)<<24) | (((y)&0xff00)<<8) | (((y)&0xff0000)>>8) | (((y)>>24)&0xff))
+#define SWAPSHORT(y) \
+ ( (((y)&0xff)<<8) | (((y)&0xff00)>>8) )
+
+
+extern FILE *sf_readfile; /* dump file being read from */
+extern FILE *sf_writefile; /* dump file being written to */
+
+int sf_read_init();
+int sf_read();
+int sf_next_packet();
+void sf_write_init();
+void sf_write();
+void sf_err();
+
+#define SFERR_TRUNC 1
+#define SFERR_BADVERSION 2
+#define SFERR_BADF 3
+#define SFERR_EOF 4 /* not really an error, just a status */
+
diff --git a/usr.sbin/tcpdump/tcpdump/tcpdump.1 b/usr.sbin/tcpdump/tcpdump/tcpdump.1
new file mode 100644
index 0000000..7ba0fb9
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/tcpdump.1
@@ -0,0 +1,1067 @@
+.\" @(#) $Header: /home/cvs/386BSD/src/contrib/tcpdump/tcpdump/tcpdump.1,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)
+.\"
+.\" Copyright (c) 1988, 1989, 1990, 1991, 1992
+.\" The Regents 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.
+.\"
+.TH TCPDUMP 1 "4 Jan 1992"
+.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 \-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
+.BR "src and 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 ip ,
+.BR arp ,
+.BR rarp ,
+.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
+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 (\\).
+.IP "\fBip\fR, \fBarp\fR, \fBrarp\fR"
+Abbreviations for:
+.in +.5i
+.nf
+\fBether proto \fIp\fR
+.fi
+.in -.5i
+where \fIp\fR is one of the above 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, 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[2: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 opertations.
+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 (`\fBand\fP').
+.IP
+Alternation (`\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
+\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
+.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\fP
+.sp .5
+\f(CWvs.e2766 > helios.nfs: 136 readdir fh 6.5197 8192 bytes @ 0
+helios.nfs > vs.e2766: reply ok 384
+vs.e2767 > helios.nfs: 136 lookup fh 6.5197 `RCS'\fP
+.sp .5
+.fi
+.RE
+In the first line, host \fIvs\fP sends a transaction with id \fIe2766\fP
+to \fIhelios\fP (note that the number following the src host is a
+transaction id, \fInot\fP the source port). The request was 136 bytes,
+excluding the UDP and IP headers. The operation was a \fIreaddir\fP
+(read directory) on file handle (\fIfh\fP) 6.5197. 8192 bytes are
+read, starting at offset 0. \fIHelios\fP replies `ok' with 384
+bytes of data. (The design of Sun's RPC protocol makes it difficult to
+interpret replies. I don't bother.)
+.LP
+In the third line, \fIvs\fP asks \fIhelios\fP to lookup the name
+`\fIRCS\fP' in directory file 6.5197. Note that the data printed
+depends on the operation type. The format is intended to be self
+explanatory (at least, to me) if read in conjunction with
+an NFS protocol spec.
+.LP
+Note that NFS requests are very large and the above won't be printed
+unless \fIsnaplen\fP is increased. I use `\fB\-s 192\fP' to watch
+NFS traffic.
+
+.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)).
+As of this writing, Ultrix does not let you
+watch either your own outbound or inbound traffic.
+.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).
diff --git a/usr.sbin/tcpdump/tcpdump/tcpdump.c b/usr.sbin/tcpdump/tcpdump/tcpdump.c
new file mode 100644
index 0000000..9a0ccc4
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/tcpdump.c
@@ -0,0 +1,347 @@
+/*
+ * 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: (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) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
+static char rcsid[] =
+ "@(#)$Header: tcpdump.c,v 1.68 92/06/02 17:57:41 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 <stdio.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <netinet/in.h>
+
+#include <net/bpf.h>
+
+#include "interface.h"
+#include "savefile.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 dflag; /* print filter code */
+
+char *program_name;
+
+long thiszone; /* gmt to local correction */
+
+static void cleanup();
+
+/* Length of saved portion of packet. */
+int snaplen = DEFAULT_SNAPLEN;
+
+static int if_fd = -1;
+
+struct printer {
+ void (*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 },
+ { 0, 0 },
+};
+
+void
+(*lookup_printer(type))()
+ 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 */
+}
+
+void
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct bpf_program *parse();
+ void bpf_dump();
+
+ int cnt = -1, i;
+ struct timeb zt;
+ struct bpf_program *fcode;
+ int op;
+ void (*printit)();
+ char *infile = 0;
+ char *cmdbuf;
+ int linktype;
+ int err;
+ u_long localnet;
+ u_long netmask;
+
+ char *RFileName = 0; /* -r argument */
+ char *WFileName = 0; /* -w argument */
+
+ char *device = 0;
+
+ int precision = clock_sigfigs();
+
+ extern char *optarg;
+ extern int optind, opterr;
+
+ program_name = argv[0];
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "c:defF:i:lnNOpqr:s:Stvw: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 '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) {
+ struct timeval now;
+ struct timezone tz;
+
+ if (gettimeofday(&now, &tz) < 0) {
+ perror("tcpdump: gettimeofday");
+ exit(1);
+ }
+ thiszone = tz.tz_minuteswest * -60;
+ if (localtime((time_t *)&now.tv_sec)->tm_isdst)
+ thiszone += 3600;
+ }
+
+ if (RFileName) {
+ /*
+ * 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());
+
+ err = sf_read_init(RFileName, &linktype, &thiszone, &snaplen,
+ &precision);
+ if (err)
+ sf_err(err);
+ localnet = 0;
+ netmask = 0;
+ if (fflag != 0)
+ error("-f and -r options are incompatible");
+ } else {
+ if (device == 0) {
+ device = lookup_device();
+ if (device == 0)
+ error("can't find any interfaces");
+ }
+ if_fd = initdevice(device, pflag, &linktype);
+ lookup_net(device, &localnet, &netmask);
+ /*
+ * Let user own process after socket has been opened.
+ */
+ setuid(getuid());
+ }
+
+ if (infile)
+ cmdbuf = read_infile(infile);
+ else
+ cmdbuf = copy_argv(&argv[optind]);
+
+ fcode = parse(cmdbuf, Oflag, linktype, netmask);
+ 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);
+
+ printit = lookup_printer(linktype);
+
+ if (WFileName) {
+ sf_write_init(WFileName, linktype, thiszone, snaplen,
+ precision);
+ printit = sf_write;
+ }
+ if (RFileName) {
+ err = sf_read(fcode, cnt, snaplen, printit);
+ if (err)
+ sf_err(err);
+ } else {
+ fprintf(stderr, "%s: listening on %s\n", program_name, device);
+ fflush(stderr);
+ readloop(cnt, if_fd, fcode, printit);
+ }
+ exit(0);
+}
+
+/* make a clean exit on interrupts */
+static void
+cleanup()
+{
+ if (if_fd >= 0) {
+ putc('\n', stderr);
+ wrapup(if_fd);
+ }
+ exit(0);
+}
+
+void
+default_print(sp, length)
+ register u_short *sp;
+ register int length;
+{
+ register u_int i;
+ register int nshorts;
+
+ nshorts = (unsigned) 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/tcpdump/tcpgram.y b/usr.sbin/tcpdump/tcpdump/tcpgram.y
new file mode 100644
index 0000000..da235d0
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/tcpgram.y
@@ -0,0 +1,232 @@
+%{
+/*
+ * 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.
+ *
+ * Grammar for tcpdump.
+ */
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: tcpgram.y,v 1.29 92/03/17 13:45:08 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include "interface.h"
+
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "gencode.h"
+
+#define QSET(q, p, d, a) (q).proto = (p),\
+ (q).dir = (d),\
+ (q).addr = (a)
+
+int n_errors = 0;
+
+static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
+
+static void
+yyerror()
+{
+ ++n_errors;
+}
+
+%}
+
+%union {
+ int i;
+ u_long h;
+ u_char *e;
+ char *s;
+ struct stmt *stmt;
+ struct arth *a;
+ struct {
+ struct qual q;
+ struct block *b;
+ } blk;
+ struct block *rblk;
+}
+
+%type <blk> expr id nid pid term rterm qid
+%type <blk> head
+%type <i> pqual dqual aqual ndaqual
+%type <a> arth narth
+%type <i> byteop pname pnum relop irelop
+%type <blk> and or paren not null prog
+%type <rblk> other
+
+%token DST SRC HOST GATEWAY
+%token NET PORT LESS GREATER PROTO BYTE
+%token ARP RARP IP TCP UDP ICMP
+%token TK_BROADCAST TK_MULTICAST
+%token NUM
+%token LINK
+%token GEQ LEQ NEQ
+%token ID EID HID
+%token LSH RSH
+%token LEN
+
+%type <s> ID
+%type <e> EID
+%type <h> HID
+%type <i> NUM
+
+%left OR AND
+%nonassoc '!'
+%left '|'
+%left '&'
+%left LSH RSH
+%left '+' '-'
+%left '*' '/'
+%nonassoc UMINUS
+%%
+prog: null expr
+{
+ finish_parse($2.b);
+}
+ | null
+ ;
+null: /* null */ { $$.q = qerr; }
+ ;
+expr: term
+ | expr and term { gen_and($1.b, $3.b); $$ = $3; }
+ | expr and id { gen_and($1.b, $3.b); $$ = $3; }
+ | expr or term { gen_or($1.b, $3.b); $$ = $3; }
+ | expr or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+and: AND { $$ = $<blk>0; }
+ ;
+or: OR { $$ = $<blk>0; }
+ ;
+id: nid
+ | pnum { $$.b = gen_ncode((u_long)$1,
+ $$.q = $<blk>0.q); }
+ | paren pid ')' { $$ = $2; }
+ ;
+nid: ID { $$.b = gen_scode($1, $$.q = $<blk>0.q); }
+ | HID { $$.b = gen_ncode($1, $$.q = $<blk>0.q); }
+ | EID { $$.b = gen_ecode($1, $$.q = $<blk>0.q); }
+ | not id { gen_not($2.b); $$ = $2; }
+ ;
+not: '!' { $$ = $<blk>0; }
+ ;
+paren: '(' { $$ = $<blk>0; }
+ ;
+pid: nid
+ | qid and id { gen_and($1.b, $3.b); $$ = $3; }
+ | qid or id { gen_or($1.b, $3.b); $$ = $3; }
+ ;
+qid: pnum { $$.b = gen_ncode((u_long)$1,
+ $$.q = $<blk>0.q); }
+ | pid
+ ;
+term: rterm
+ | not term { gen_not($2.b); $$ = $2; }
+ ;
+head: pqual dqual aqual { QSET($$.q, $1, $2, $3); }
+ | pqual dqual { QSET($$.q, $1, $2, Q_DEFAULT); }
+ | pqual aqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ | pqual PROTO { QSET($$.q, $1, Q_DEFAULT, Q_PROTO); }
+ | pqual ndaqual { QSET($$.q, $1, Q_DEFAULT, $2); }
+ ;
+rterm: head id { $$ = $2; }
+ | paren expr ')' { $$.b = $2.b; $$.q = $1.q; }
+ | pname { $$.b = gen_proto_abbrev($1); $$.q = qerr; }
+ | arth relop arth { $$.b = gen_relation($2, $1, $3, 0);
+ $$.q = qerr; }
+ | arth irelop arth { $$.b = gen_relation($2, $1, $3, 1);
+ $$.q = qerr; }
+ | other { $$.b = $1; $$.q = qerr; }
+ ;
+/* protocol level qualifiers */
+pqual: pname
+ | { $$ = Q_DEFAULT; }
+ ;
+/* 'direction' qualifiers */
+dqual: SRC { $$ = Q_SRC; }
+ | DST { $$ = Q_DST; }
+ | SRC OR DST { $$ = Q_OR; }
+ | DST OR SRC { $$ = Q_OR; }
+ | SRC AND DST { $$ = Q_AND; }
+ | DST AND SRC { $$ = Q_AND; }
+ ;
+/* address type qualifiers */
+aqual: HOST { $$ = Q_HOST; }
+ | NET { $$ = Q_NET; }
+ | PORT { $$ = Q_PORT; }
+ ;
+/* non-directional address type qualifiers */
+ndaqual: GATEWAY { $$ = Q_GATEWAY; }
+ ;
+pname: LINK { $$ = Q_LINK; }
+ | IP { $$ = Q_IP; }
+ | ARP { $$ = Q_ARP; }
+ | RARP { $$ = Q_RARP; }
+ | TCP { $$ = Q_TCP; }
+ | UDP { $$ = Q_UDP; }
+ | ICMP { $$ = Q_ICMP; }
+ ;
+other: pqual TK_BROADCAST { $$ = gen_broadcast($1); }
+ | pqual TK_MULTICAST { $$ = gen_multicast($1); }
+ | LESS NUM { $$ = gen_less($2); }
+ | GREATER NUM { $$ = gen_greater($2); }
+ | BYTE NUM byteop NUM { $$ = gen_byteop($3, $2, $4); }
+ ;
+relop: '>' { $$ = BPF_JGT; }
+ | GEQ { $$ = BPF_JGE; }
+ | '=' { $$ = BPF_JEQ; }
+ ;
+irelop: LEQ { $$ = BPF_JGT; }
+ | '<' { $$ = BPF_JGE; }
+ | NEQ { $$ = BPF_JEQ; }
+ ;
+arth: pnum { $$ = gen_loadi($1); }
+ | narth
+ ;
+narth: pname '[' arth ']' { $$ = gen_load($1, $3, 1); }
+ | pname '[' arth ':' NUM ']' { $$ = gen_load($1, $3, $5); }
+ | arth '+' arth { $$ = gen_arth(BPF_ADD, $1, $3); }
+ | arth '-' arth { $$ = gen_arth(BPF_SUB, $1, $3); }
+ | arth '*' arth { $$ = gen_arth(BPF_MUL, $1, $3); }
+ | arth '/' arth { $$ = gen_arth(BPF_DIV, $1, $3); }
+ | arth '&' arth { $$ = gen_arth(BPF_AND, $1, $3); }
+ | arth '|' arth { $$ = gen_arth(BPF_OR, $1, $3); }
+ | arth LSH arth { $$ = gen_arth(BPF_LSH, $1, $3); }
+ | arth RSH arth { $$ = gen_arth(BPF_RSH, $1, $3); }
+ | '-' arth %prec UMINUS { $$ = gen_neg($2); }
+ | paren narth ')' { $$ = $2; }
+ | LEN { $$ = gen_loadlen(); }
+ ;
+byteop: '&' { $$ = '&'; }
+ | '|' { $$ = '|'; }
+ | '<' { $$ = '<'; }
+ | '>' { $$ = '>'; }
+ | '=' { $$ = '='; }
+ ;
+pnum: NUM
+ | paren pnum ')' { $$ = $2; }
+ ;
+%%
diff --git a/usr.sbin/tcpdump/tcpdump/tcplex.l b/usr.sbin/tcpdump/tcpdump/tcplex.l
new file mode 100644
index 0000000..3db8a32
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/tcplex.l
@@ -0,0 +1,144 @@
+%{
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: /home/ncvs/src/usr.sbin/tcpdump/tcpdump/tcplex.l,v 1.1.1.1 1993/06/12 14:42:05 rgrimes Exp $ (LBL)";
+#endif
+
+/*
+ * Compiling with gcc under SunOS will cause problems unless we have this
+ * cruft here. The flex skeleton includes stddef.h which defines these types
+ * (under gcc). They will conflict with Sun's definitions in sys/types.h.
+ */
+#define size_t xxxsize_t
+#define ptrdiff_t xxxptrdiff_t
+#define wchar_t xxxwchar_t
+#include <sys/types.h>
+#undef size_t
+#undef ptrdiff_t
+#undef wchar_t
+
+#include "nametoaddr.h"
+
+/*
+ * We need bpf since enum bpf_code is in YYSTYPE.
+ */
+#include <sys/time.h>
+#include <net/bpf.h>
+
+#include "gencode.h"
+#include "y.tab.h" /* "tokdefs.h" */
+
+#ifdef FLEX_SCANNER
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max)\
+ {\
+ char *src = in_buffer;\
+ int i;\
+\
+ if (*src == 0)\
+ result = YY_NULL;\
+ else {\
+ for (i = 0; *src && i < max; ++i)\
+ buf[i] = *src++;\
+ in_buffer += i;\
+ result = i;\
+ }\
+ }
+#else
+#undef getc
+#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++)
+#endif
+
+extern YYSTYPE yylval;
+static char *in_buffer;
+
+%}
+
+N ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
+B ([0-9A-Fa-f][0-9A-Fa-f]?)
+
+%a 3000
+
+%%
+dst return DST;
+src return SRC;
+
+link|ether|ppp|slip return LINK;
+arp return ARP;
+rarp return RARP;
+ip return IP;
+tcp return TCP;
+udp return UDP;
+icmp return ICMP;
+
+host return HOST;
+net return NET;
+port return PORT;
+proto return PROTO;
+
+gateway return GATEWAY;
+
+less return LESS;
+greater return GREATER;
+byte return BYTE;
+broadcast return TK_BROADCAST;
+multicast return TK_MULTICAST;
+
+and return AND;
+or return OR;
+not return '!';
+
+len return LEN;
+
+[ \n\t] ;
+[+\-*/:\[\]!<>()&|=] return yytext[0];
+">=" return GEQ;
+"<=" return LEQ;
+"!=" return NEQ;
+"==" return '=';
+"<<" return LSH;
+">>" return RSH;
+{N} { yylval.i = stoi(yytext); return NUM; }
+({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
+ yylval.h = atoin(yytext); return HID;
+}
+{B}:{B}:{B}:{B}:{B}:{B} { yylval.e = ETHER_aton(yytext); return EID; }
+{B}:+({B}:+)+ { error("bogus ethernet address %s", yytext); }
+[A-Za-z][-_.A-Za-z0-9]* { yylval.s = yytext; return ID; }
+"\\"[^ !()\n\t]+ { yylval.s = yytext + 1; return ID; }
+[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ { error("illegal token: %s\n", yytext); }
+. { error("illegal char '%c'", *yytext); }
+%%
+void
+lex_init(buf)
+ char *buf;
+{
+ in_buffer = buf;
+}
+int
+yywrap()
+/* so we don't need -ll */
+{
+ return 1;
+}
diff --git a/usr.sbin/tcpdump/tcpdump/util.c b/usr.sbin/tcpdump/tcpdump/util.c
new file mode 100644
index 0000000..ec58c3f
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpdump/util.c
@@ -0,0 +1,278 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: util.c,v 1.12 91/10/28 22:09:31 mccanne Exp $ (LBL)";
+#endif
+
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <varargs.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "interface.h"
+
+/* Hex digit to integer. */
+static inline int
+xdtoi(c)
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (islower(c))
+ return c - 'a' + 10;
+ else
+ return c - 'A' + 10;
+}
+
+/*
+ * Convert string to integer. Just like atoi(), but checks for
+ * preceding 0x or 0 and uses hex or octal instead of decimal.
+ */
+int
+stoi(s)
+ char *s;
+{
+ int base = 10;
+ int n = 0;
+
+ if (*s == '0') {
+ if (s[1] == 'x' || s[1] == 'X') {
+ s += 2;
+ base = 16;
+ }
+ else {
+ base = 8;
+ s += 1;
+ }
+ }
+ while (*s)
+ n = n * base + xdtoi(*s++);
+
+ return n;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Print the timestamp
+ */
+void
+ts_print(tvp)
+ register struct timeval *tvp;
+{
+ register int i;
+
+ if (tflag > 0) {
+ /* Default */
+ i = (tvp->tv_sec + thiszone) % 86400;
+ (void)printf("%02d:%02d:%02d.%06d ",
+ i / 3600, (i % 3600) / 60, i % 60, tvp->tv_usec);
+ } else if (tflag < 0) {
+ /* Unix timeval style */
+ (void)printf("%d.%06d ", tvp->tv_sec, tvp->tv_usec);
+ }
+}
+
+#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
+
+static char *
+stripdir(s)
+ register char *s;
+{
+ register char *cp;
+ char *rindex();
+
+ cp = rindex(s, '/');
+ return (cp != 0) ? cp + 1 : s;
+}
+
+/* VARARGS */
+void
+error(va_alist)
+ va_dcl
+{
+ register char *cp;
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: ", stripdir(program_name));
+
+ va_start(ap);
+ cp = va_arg(ap, char *);
+ (void)vfprintf(stderr, cp, ap);
+ va_end(ap);
+ if (*cp) {
+ cp += strlen(cp);
+ if (cp[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+ exit(1);
+ /* NOTREACHED */
+}
+
+/* VARARGS */
+void
+warning(va_alist)
+ va_dcl
+{
+ register char *cp;
+ va_list ap;
+
+ (void)fprintf(stderr, "%s: warning: ", stripdir(program_name));
+
+ va_start(ap);
+ cp = va_arg(ap, char *);
+ (void)vfprintf(stderr, cp, ap);
+ va_end(ap);
+ if (*cp) {
+ cp += strlen(cp);
+ if (cp[-1] != '\n')
+ (void)fputc('\n', stderr);
+ }
+}
+
+
+/*
+ * Copy arg vector into a new buffer, concatenating arguments with spaces.
+ */
+char *
+copy_argv(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++) {
+ while (*dst++ = *src++)
+ ;
+ dst[-1] = ' ';
+ }
+ dst[-1] = '\0';
+
+ return buf;
+}
+
+char *
+read_infile(fname)
+ 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((unsigned)buf.st_size);
+ if (read(fd, p, (int)buf.st_size) != buf.st_size)
+ error("problem reading '%s'", fname);
+
+ return p;
+}
+
+/*
+ * Left justify 'addr' and return its resulting network mask.
+ */
+u_long
+net_mask(addr)
+ u_long *addr;
+{
+ register u_long m = 0xffffffff;
+
+ if (*addr)
+ while ((*addr & 0xff000000) == 0)
+ *addr <<= 8, m <<= 8;
+
+ return m;
+}
diff --git a/usr.sbin/tcpdump/tcpslice/Makefile b/usr.sbin/tcpdump/tcpslice/Makefile
new file mode 100644
index 0000000..55b2402
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpslice/Makefile
@@ -0,0 +1,18 @@
+# @(#)Makefile 0.1 (RWGrimes) 3/24/93
+
+PROG= tcpslice
+CFLAGS+=-DCSLIP -I. -I$(.CURDIR)/../tcpdump
+MAN1= tcpslice.1
+SRCS= version.c tcpslice.c gwtm2secs.c search.c \
+ savefile.c bpf_filter.c md.c util.c
+.PATH: ${.CURDIR}/../tcpdump /sys/net
+CLEANFILES+= version.c version.h
+
+version.c version.h: $(.CURDIR)/../tcpdump/VERSION
+ rm -f version.c ; \
+ sed 's/.*/char version[] = "&";/' $(.CURDIR)/../tcpdump/VERSION > version.c
+ set `sed 's/\([0-9]*\)\.\([0-9]*\).*/\1 \2/' $(.CURDIR)/../tcpdump/VERSION` ; \
+ { echo '#define VERSION_MAJOR' $$1 ; \
+ echo '#define VERSION_MINOR' $$2 ; } > version.h
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/tcpdump/tcpslice/gwtm2secs.c b/usr.sbin/tcpdump/tcpslice/gwtm2secs.c
new file mode 100644
index 0000000..aeb377f
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpslice/gwtm2secs.c
@@ -0,0 +1,75 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: gwtm2secs.c,v 1.1 92/06/02 11:35:19 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * gwtm2secs.c - convert "tm" structs for Greenwich time to Unix timestamp
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+
+static int days_in_month[] =
+ /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+
+#define IS_LEAP_YEAR(year) \
+ (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+
+time_t gwtm2secs( tm )
+struct tm *tm;
+ {
+ int i, days, year;
+
+ year = tm->tm_year;
+
+ /* Allow for year being specified with either 2 digits or 4 digits.
+ * 2-digit years are either 19xx or 20xx - a simple heuristic
+ * distinguishes them, since we can't represent any time < 1970.
+ */
+ if ( year < 100 )
+ if ( year >= 70 )
+ year += 1900;
+ else
+ year += 2000;
+
+ days = 0;
+ for ( i = 1970; i < year; ++i )
+ {
+ days += 365;
+ if ( IS_LEAP_YEAR(i) )
+ ++days;
+ }
+
+ for ( i = 0; i < tm->tm_mon; ++i )
+ days += days_in_month[i];
+
+ if ( IS_LEAP_YEAR(year) && tm->tm_mon > 1 ) /* 1 is February */
+ ++days;
+
+ days += tm->tm_mday - 1; /* -1 since days are numbered starting at 1 */
+
+ return days * 86400 + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
+ }
diff --git a/usr.sbin/tcpdump/tcpslice/search.c b/usr.sbin/tcpdump/tcpslice/search.c
new file mode 100644
index 0000000..8bea0d2
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpslice/search.c
@@ -0,0 +1,563 @@
+/*
+ * 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
+static char rcsid[] =
+ "@(#)$Header: search.c,v 1.3 92/05/01 15:14:45 vern Exp $ (LBL)";
+#endif
+
+/*
+ * search.c - supports fast searching through tcpdump files for timestamps
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "interface.h"
+#include "savefile.h"
+
+
+/* Maximum number of seconds that we can conceive of a dump file spanning. */
+#define MAX_REASONABLE_FILE_SPAN (3600*24*366) /* one year */
+
+/* Maximum packet length we ever expect to see. */
+#define MAX_REASONABLE_PACKET_LENGTH 65535
+
+/* Size of a packet header in bytes; easier than typing the sizeof() all
+ * the time ...
+ */
+#define PACKET_HDR_LEN (sizeof( struct packet_header ))
+
+/* The maximum size of a packet, including its header. */
+#define MAX_PACKET_SIZE (PACKET_HDR_LEN + snaplen)
+
+/* Number of contiguous bytes from a dumpfile in which there's guaranteed
+ * to be enough information to find a "definite" header if one exists
+ * therein. This takes 3 full packets - the first to be just misaligned
+ * (one byte short of a full packet), missing its timestamp; the second
+ * to have the legitimate timestamp; and the third to provide confirmation
+ * that the second is legit, making it a "definite" header. We could
+ * scrimp a bit here since not the entire third packet is required, but
+ * it doesn't seem worth it
+ */
+#define MAX_BYTES_FOR_DEFINITE_HEADER (3 * MAX_PACKET_SIZE)
+
+/* Maximum number of seconds that might reasonably separate two headers. */
+#define MAX_REASONABLE_HDR_SEPARATION (3600 * 24 * 7) /* one week */
+
+/* When searching a file for a packet, if we think we're within this many
+ * bytes of the packet we just search linearly. Since linear searches are
+ * probably much faster than random ones (random ones require searching for
+ * the beginning of the packet, which may be unaligned in memory), we make
+ * this value pretty hefty.
+ */
+#define STRAIGHT_SCAN_THRESHOLD (100 * MAX_PACKET_SIZE)
+
+/* Extracts a long integer from a possibly unaligned buffer containing
+ * unsigned characters.
+ */
+#define EXTRACT_LONG(buf) (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3])
+
+
+/* Given a header and an acceptable first and last time stamp, returns non-zero
+ * if the header looks reasonable and zero otherwise.
+ */
+static int reasonable_header( hdr, first_time, last_time )
+struct packet_header *hdr;
+long first_time, last_time;
+ {
+ if ( last_time == 0 )
+ last_time = first_time + MAX_REASONABLE_FILE_SPAN;
+
+ return hdr->ts.tv_sec >= first_time &&
+ hdr->ts.tv_sec <= last_time &&
+ hdr->len > 0 &&
+ hdr->len <= MAX_REASONABLE_PACKET_LENGTH &&
+ hdr->caplen > 0 &&
+ hdr->caplen <= MAX_REASONABLE_PACKET_LENGTH;
+ }
+
+
+/* Given a buffer, extracts a (properly aligned) packet header from it. */
+
+static void extract_header( buf, hdr )
+u_char *buf;
+struct packet_header *hdr;
+ {
+ hdr->ts.tv_sec = EXTRACT_LONG(buf);
+ buf += sizeof( long );
+ hdr->ts.tv_usec = EXTRACT_LONG(buf);
+ buf += sizeof( long );
+ hdr->len = EXTRACT_LONG(buf);
+ buf += sizeof( long );
+ hdr->caplen = EXTRACT_LONG(buf);
+
+ if ( sf_swapped )
+ {
+ hdr->ts.tv_sec = SWAPLONG(hdr->ts.tv_sec);
+ hdr->ts.tv_usec = SWAPLONG(hdr->ts.tv_usec);
+ hdr->len = SWAPLONG(hdr->len);
+ hdr->caplen = SWAPLONG(hdr->caplen);
+ }
+ }
+
+
+/* Search a buffer to locate the first header within it. Return values
+ * are HEADER_NONE, HEADER_CLASH, HEADER_PERHAPS, and HEADER_DEFINITELY.
+ * The first indicates that no evidence of a header was found; the second
+ * that two or more possible headers were found, neither more convincing
+ * than the other(s); the third that exactly one "possible" header was
+ * found; and the fourth that exactly one "definite" header was found.
+ *
+ * Headers are detected by looking for positions in the buffer which have
+ * reasonable timestamps and lengths. If there is enough room in the buffer
+ * for another header to follow a candidate header, a check is made for
+ * that following header. If it is present then the header is *definite*
+ * (unless another "perhaps" or "definite" header is found); if not, then
+ * the header is discarded. If there is not enough room in the buffer for
+ * another header then the candidate is *perhaps* (unless another header
+ * is subsequently found). A "tie" between a "definite" header and a
+ * "perhaps" header is resolved in favor of the definite header. Any
+ * other tie leads to HEADER_CLASH.
+ *
+ * The buffer position of the header is returned in hdrpos_addr and
+ * for convenience the corresponding header in return_hdr.
+ *
+ * first_time is the earliest possible acceptable timestamp in the
+ * header. last_time, if non-zero, is the last such timestamp. If
+ * zero, then up to MAX_REASONABLE_FILE_SPAN seconds after first_time
+ * is acceptable.
+ */
+
+#define HEADER_NONE 0
+#define HEADER_CLASH 1
+#define HEADER_PERHAPS 2
+#define HEADER_DEFINITELY 3
+
+static int find_header( buf, buf_len, first_time, last_time,
+ hdrpos_addr, return_hdr )
+u_char *buf;
+unsigned buf_len;
+long first_time, last_time;
+u_char **hdrpos_addr;
+struct packet_header *return_hdr;
+ {
+ u_char *bufptr, *bufend, *last_pos_to_try;
+ struct packet_header hdr, hdr2;
+ int status = HEADER_NONE;
+ int saw_PERHAPS_clash = 0;
+
+ /* Initially, try each buffer position to see whether it looks like
+ * a valid packet header. We may later restrict the positions we look
+ * at to avoid seeing a sequence of legitimate headers as conflicting
+ * with one another.
+ */
+ bufend = buf + buf_len;
+ last_pos_to_try = bufend - PACKET_HDR_LEN;
+
+ for ( bufptr = buf; bufptr < last_pos_to_try; ++bufptr )
+ {
+ extract_header( bufptr, &hdr );
+
+ if ( reasonable_header( &hdr, first_time, last_time ) )
+ {
+ u_char *next_header = bufptr + PACKET_HDR_LEN + hdr.caplen;
+
+ if ( next_header + PACKET_HDR_LEN < bufend )
+ { /* check for another good header */
+ extract_header( next_header, &hdr2 );
+
+ if ( reasonable_header( &hdr2, hdr.ts.tv_sec,
+ hdr.ts.tv_sec + MAX_REASONABLE_HDR_SEPARATION ) )
+ { /* a confirmed header */
+ switch ( status )
+ {
+ case HEADER_NONE:
+ case HEADER_PERHAPS:
+ status = HEADER_DEFINITELY;
+ *hdrpos_addr = bufptr;
+ *return_hdr = hdr;
+
+ /* Make sure we don't demote this "definite"
+ * to a "clash" if we stumble across its
+ * successor.
+ */
+ last_pos_to_try = next_header - PACKET_HDR_LEN;
+ break;
+
+ case HEADER_DEFINITELY:
+ return HEADER_CLASH;
+
+ default:
+ error( "bad status in find_header()" );
+ }
+ }
+
+ /* ... else the header is bogus - we've verified that it's
+ * not followed by a reasonable header.
+ */
+ }
+
+ else
+ { /* can't check for another good header */
+ switch ( status )
+ {
+ case HEADER_NONE:
+ status = HEADER_PERHAPS;
+ *hdrpos_addr = bufptr;
+ *return_hdr = hdr;
+ break;
+
+ case HEADER_PERHAPS:
+ /* We don't immediately turn this into a
+ * clash because perhaps we'll later see a
+ * "definite" which will save us ...
+ */
+ saw_PERHAPS_clash = 1;
+ break;
+
+ case HEADER_DEFINITELY:
+ /* Keep the definite in preference to this one. */
+ break;
+
+ default:
+ error( "bad status in find_header()" );
+ }
+ }
+ }
+ }
+
+ if ( status == HEADER_PERHAPS && saw_PERHAPS_clash )
+ status = HEADER_CLASH;
+
+ return status;
+ }
+
+
+/* Positions the sf_readfile stream such that the next sf_read() will
+ * read the final full packet in the file. Returns non-zero if
+ * successful, zero if unsuccessful. If successful, returns the
+ * timestamp of the last packet in last_timestamp.
+ *
+ * Note that this routine is a special case of sf_find_packet(). In
+ * order to use sf_find_packet(), one first must use this routine in
+ * order to give sf_find_packet() an upper bound on the timestamps
+ * present in the dump file.
+ */
+int sf_find_end( first_timestamp, last_timestamp )
+struct timeval *first_timestamp;
+struct timeval *last_timestamp;
+ {
+ long first_time = first_timestamp->tv_sec;
+ unsigned num_bytes;
+ u_char *buf, *bufpos, *bufend;
+ u_char *hdrpos;
+ struct packet_header hdr, successor_hdr;
+ int status;
+
+ /* Allow enough room for at least two full (untruncated) packets,
+ * perhaps followed by a truncated packet, so we have a shot at
+ * finding a "definite" header and following its chain to the
+ * end of the file.
+ */
+ num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER;
+ if ( fseek( sf_readfile, (long) -num_bytes, 2 ) < 0 )
+ return 0;
+
+ buf = (u_char *)malloc((unsigned) num_bytes);
+ if ( ! buf )
+ return 0;
+
+ status = 0;
+ bufpos = buf;
+ bufend = buf + num_bytes;
+
+ if ( fread( (char *) bufpos, num_bytes, 1, sf_readfile ) != 1 )
+ goto done;
+
+ if ( find_header( bufpos, num_bytes, first_time, 0L, &hdrpos, &hdr ) !=
+ HEADER_DEFINITELY )
+ goto done;
+
+ /* Okay, we have a definite header in our hands. Follow its
+ * chain till we find the last valid packet in the file ...
+ */
+ for ( ; ; )
+ {
+ /* move to the next header position */
+ bufpos = hdrpos + PACKET_HDR_LEN + hdr.caplen;
+
+ /* bufpos now points to a candidate packet, which if valid
+ * should replace the current packet pointed to by hdrpos as
+ * the last valid packet ...
+ */
+ if ( bufpos >= bufend - PACKET_HDR_LEN )
+ /* not enough room for another header */
+ break;
+
+ extract_header( bufpos, &successor_hdr );
+
+ first_time = hdr.ts.tv_sec;
+ if ( ! reasonable_header( &successor_hdr, first_time, 0L ) )
+ /* this bodes ill - it means bufpos is perhaps a
+ * bogus packet header after all ...
+ */
+ break;
+
+ /* Note that the following test is for whether the next
+ * packet starts at a position > bufend, *not* for a
+ * position >= bufend. If this is the last packet in the
+ * file and there isn't a subsequent partial packet, then
+ * we expect the first buffer position beyond this packet
+ * to be just beyond the end of the buffer, i.e., at bufend
+ * itself.
+ */
+ if ( bufpos + PACKET_HDR_LEN + successor_hdr.caplen > bufend )
+ /* the packet is truncated */
+ break;
+
+ /* Accept this packet as fully legit. */
+ hdrpos = bufpos;
+ hdr = successor_hdr;
+ }
+
+ /* Success! Last valid packet is at hdrpos. */
+ *last_timestamp = hdr.ts;
+ status = 1;
+
+ /* Seek so that the next read will start at last valid packet. */
+ if ( fseek( sf_readfile, (long) -(bufend - hdrpos), 2 ) < 0 )
+ error( "final fseek() failed in sf_find_end()" );
+
+ done:
+ free( (char *) buf );
+
+ return status;
+ }
+
+
+/* Takes two timeval's and returns the difference, tv2 - tv1, as a double. */
+
+static double timeval_diff( tv1, tv2 )
+struct timeval *tv1, *tv2;
+ {
+ double result = (tv2->tv_sec - tv1->tv_sec);
+ result += (tv2->tv_usec - tv1->tv_usec) / 1000000.0;
+
+ return result;
+ }
+
+
+/* Returns true if timestamp t1 is chronologically less than timestamp t2. */
+
+int sf_timestamp_less_than( t1, t2 )
+struct timeval *t1, *t2;
+ {
+ return t1->tv_sec < t2->tv_sec ||
+ (t1->tv_sec == t2->tv_sec &&
+ t1->tv_usec < t2->tv_usec);
+ }
+
+
+/* Given two timestamps on either side of desired_time and their positions,
+ * returns the interpolated position of the desired_time packet. Returns a
+ * negative value if the desired_time is outside the given range.
+ */
+
+static
+long interpolated_position( min_time, min_pos, max_time, max_pos, desired_time )
+struct timeval *min_time, *max_time, *desired_time;
+long min_pos, max_pos;
+ {
+ double full_span = timeval_diff( max_time, min_time );
+ double desired_span = timeval_diff( desired_time, min_time );
+ long full_span_pos = max_pos - min_pos;
+ double fractional_offset = desired_span / full_span;
+
+ if ( fractional_offset < 0.0 || fractional_offset > 1.0 )
+ return -1;
+
+ return min_pos + (long) (fractional_offset * (double) full_span_pos);
+ }
+
+
+/* Reads packets linearly until one with a time >= the given desired time
+ * is found; positions the dump file so that the next read will start
+ * at the given packet. Returns non-zero on success, 0 if an EOF was
+ * first encountered.
+ */
+
+static int read_up_to( desired_time )
+struct timeval *desired_time;
+ {
+ int status = 1;
+ struct packet_header hdr;
+ u_char *buf;
+ long pos;
+
+ buf = (u_char *) malloc( (unsigned) snaplen );
+
+ for ( ; ; )
+ {
+ struct timeval *timestamp;
+
+ pos = ftell( sf_readfile );
+ status = sf_next_packet( &hdr, buf, snaplen );
+
+ if ( status )
+ {
+ if ( status == SFERR_EOF )
+ {
+ status = 0;
+ break;
+ }
+
+ error( "bad status %d in read_up_to()", status );
+ }
+
+ timestamp = &hdr.ts;
+
+ if ( ! sf_timestamp_less_than( timestamp, desired_time ) )
+ break;
+ }
+
+ if ( fseek( sf_readfile, pos, 0 ) < 0 )
+ error( "fseek() failed in read_up_to()" );
+
+ free( (char *) buf );
+
+ return status;
+ }
+
+
+/* Positions the sf_readfile stream so that the next sf_read() will
+ * return the first packet with a time greater than or equal to
+ * desired_time. desired_time must be greater than min_time and less
+ * than max_time, which should correspond to actual packets in the
+ * file. min_pos is the file position (byte offset) corresponding to
+ * the min_time packet and max_pos is the same for the max_time packet.
+ *
+ * Returns non-zero on success, 0 if the given position is beyond max_pos.
+ *
+ * NOTE: when calling this routine, the sf_readfile stream *must* be
+ * already aligned so that the next call to sf_next_packet() will yield
+ * a valid packet.
+ */
+
+int sf_find_packet( min_time, min_pos, max_time, max_pos, desired_time )
+struct timeval *min_time, *max_time;
+long min_pos, max_pos;
+struct timeval *desired_time;
+ {
+ int status = 1;
+ struct timeval min_time_copy, max_time_copy;
+ unsigned num_bytes = MAX_BYTES_FOR_DEFINITE_HEADER;
+ int num_bytes_read;
+ long desired_pos, present_pos;
+ u_char *buf, *hdrpos;
+ struct packet_header hdr;
+
+ buf = (u_char *) malloc( num_bytes );
+ if ( ! buf )
+ error( "malloc() failured in sf_find_packet()" );
+
+ min_time_copy = *min_time;
+ min_time = &min_time_copy;
+
+ max_time_copy = *max_time;
+ max_time = &max_time_copy;
+
+ for ( ; ; ) /* loop until positioned correctly */
+ {
+ desired_pos =
+ interpolated_position( min_time, min_pos,
+ max_time, max_pos,
+ desired_time );
+
+ if ( desired_pos < 0 )
+ {
+ status = 0;
+ break;
+ }
+
+ present_pos = ftell( sf_readfile );
+
+ if ( present_pos <= desired_pos &&
+ desired_pos - present_pos < STRAIGHT_SCAN_THRESHOLD )
+ { /* we're close enough to just blindly read ahead */
+ status = read_up_to( desired_time );
+ break;
+ }
+
+ /* Undershoot the target a little bit - it's much easier to
+ * then scan straight forward than to try to read backwards ...
+ */
+ desired_pos -= STRAIGHT_SCAN_THRESHOLD / 2;
+ if ( desired_pos < min_pos )
+ desired_pos = min_pos;
+
+ if ( fseek( sf_readfile, desired_pos, 0 ) < 0 )
+ error( "fseek() failed in sf_find_packet()" );
+
+ num_bytes_read =
+ fread( (char *) buf, 1, num_bytes, sf_readfile );
+
+ if ( num_bytes_read == 0 )
+ /* This shouldn't ever happen because we try to
+ * undershoot, unless the dump file has only a
+ * couple packets in it ...
+ */
+ error( "fread() failed in sf_find_packet()" );
+
+ if ( find_header( buf, num_bytes, min_time->tv_sec,
+ max_time->tv_sec, &hdrpos, &hdr ) !=
+ HEADER_DEFINITELY )
+ error( "can't find header at position %ld in dump file",
+ desired_pos );
+
+ /* Correct desired_pos to reflect beginning of packet. */
+ desired_pos += (hdrpos - buf);
+
+ /* Seek to the beginning of the header. */
+ if ( fseek( sf_readfile, desired_pos, 0 ) < 0 )
+ error( "fseek() failed in sf_find_packet()" );
+
+ if ( sf_timestamp_less_than( &hdr.ts, desired_time ) )
+ { /* too early in the file */
+ *min_time = hdr.ts;
+ min_pos = desired_pos;
+ }
+
+ else if ( sf_timestamp_less_than( desired_time, &hdr.ts ) )
+ { /* too late in the file */
+ *max_time = hdr.ts;
+ max_pos = desired_pos;
+ }
+
+ else
+ /* got it! */
+ break;
+ }
+
+ free( (char *) buf );
+
+ return status;
+ }
diff --git a/usr.sbin/tcpdump/tcpslice/tcpslice.1 b/usr.sbin/tcpdump/tcpslice/tcpslice.1
new file mode 100644
index 0000000..b130f2c
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpslice/tcpslice.1
@@ -0,0 +1,260 @@
+.\" @(#) $Header: tcpslice.1,v 1.2 91/10/16 11:42:46 vern Exp $ (LBL)
+.\"
+.\" 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.
+.\"
+.TH TCPSLICE 1 "14 Oct 1991"
+.SH NAME
+tcpslice \- extract pieces of and/or glue together tcpdump files
+.SH SYNOPSIS
+.na
+.B tcpslice
+[
+.B \-dRrt
+] [
+.B \-w
+.I file
+]
+.br
+.ti +9
+[
+.I start-time
+[
+.I end-time
+] ]
+.I file ...
+.br
+.ad
+.SH DESCRIPTION
+.LP
+.I Tcpslice
+is a program for extracting portions of packet-trace files generated using
+\fItcpdump(l)\fP's
+.B \-w
+flag.
+It can also be used to glue together several such files, as discussed
+below.
+.LP
+The basic operation of
+.I tcpslice
+is to copy to
+.I stdout
+all packets from its input file(s) whose timestamps fall
+within a given range. The starting and ending times of the range
+may be specified on the command line. All ranges are inclusive.
+The starting time defaults
+to the time of the first packet in the first input file; we call
+this the
+.I first time.
+The ending time defaults to ten years after the starting time.
+Thus, the command
+.I tcpslice trace-file
+simply copies
+.I trace-file
+to \fIstdout\fP (assuming the file does not include more than
+ten years' worth of data).
+.LP
+There are a number of ways to specify times. The first is using
+Unix timestamps of the form
+.I sssssssss.uuuuuu
+(this is the format specified by \fItcpdump\fP's
+.B \-tt
+flag).
+For example,
+.B 654321098.7654
+specifies 38 seconds and 765,400 microseconds
+after 8:51PM PDT, Sept. 25, 1990.
+.LP
+All examples in this manual are given
+for PDT times, but when displaying times and interpreting times symbolically
+as discussed below,
+.I tcpslice
+uses the local timezone, regardless of the timezone in which the \fItcpdump\fP
+file was generated. The daylight-savings setting used is that which is
+appropriate for the local timezone at the date in question. For example,
+times associated with summer months will usually include daylight-savings
+effects, and those with winter months will not.
+.LP
+Times may also be specified relative
+to either the
+.I first time
+(when specifying a starting time)
+or the starting time (when specifying an ending time)
+by preceding a numeric value in seconds with a `+'.
+For example, a starting time of
+.B +200
+indicates 200 seconds after the
+.I first time,
+and the two arguments
+.B +200 +300
+indicate from 200 seconds after the
+.I first time
+through 500 seconds after the
+.I first time.
+.LP
+Times may also be specified in terms of years (y), months (m), days (d),
+hours (h), minutes (m), seconds (s), and microseconds(u). For example,
+the Unix timestamp 654321098.7654 discussed above could also be expressed
+as
+.B 90y9m25d20h51m38s765400u.
+.LP
+When specifying times using this style, fields that are omitted default
+as follows. If the omitted field is a unit
+.I greater
+than that of the first specified field, then its value defaults to
+the corresponding value taken from either
+.I first time
+(if the starting time is being specified) or the starting time
+(if the ending time is being specified).
+If the omitted field is a unit
+.I less
+than that of the first specified field, then it defaults to zero.
+For example, suppose that the input file has a
+.I first time
+of the Unix timestamp mentioned above, i.e., 38 seconds and 765,400 microseconds
+after 8:51PM PDT, Sept. 25, 1990. To specify 9:36PM PDT (exactly) on the
+same date we could use
+.B 21h36m.
+To specify a range from 9:36PM PDT through 1:54AM PDT the next day we
+could use
+.B 21h36m 26d1h54m.
+.LP
+Relative times can also be specified when using the
+.I ymdhmsu
+format. Omitted fields then default to 0 if the unit of the field is
+.I greater
+than that of the first specified field, and to the corresponding value
+taken from either the
+.I first time
+or the starting time if the omitted field's unit is
+.I less
+than that of the first specified field. Given a
+.I first time
+of the Unix timestamp mentioned above,
+.B 22h +1h10m
+specifies a range from 10:00PM PDT on that date through 11:10PM PDT, and
+.B +1h +1h10m
+specifies a range from 38.7654 seconds after 9:51PM PDT through 38.7654
+seconds after 11:01PM PDT. The first hour of the file could be extracted
+using
+.B +0 +1h.
+.LP
+Note that with the
+.I ymdhmsu
+format there is an ambiguity between using
+.I m
+for `month' or for `minute'. The ambiguity is resolved as follows: if an
+.I m
+field is followed by a
+.I d
+field then it is interpreted as specifying months; otherwise it
+specifies minutes.
+.LP
+If more than one input file is specified then
+.I tcpslice
+first copies packets lying in the given range from the first file; it
+then increases the starting time of the range to lie just beyond the
+timestamp of the last packet in the first file, repeats the process
+with the second file, and so on. Thus files with interleaved packets
+are
+.I not
+merged. For a given file, only packets that are newer than any in the
+preceding files will be considered. This mechanism avoids any possibility
+of a packet occurring more than once in the output.
+.SH OPTIONS
+.LP
+If any of
+.B \-R,
+.B \-r
+or
+.B \-t
+are specified then
+.I tcpslice
+reports the timestamps of the first and last packets in each input file
+and exits. Only one of these three options may be specified.
+.TP
+.B \-d
+Dump the start and end times specified by the given range and
+exit. This option is useful for checking that the given range actually
+specifies the times you think it does. If one of
+.B \-R,
+.B \-r
+or
+.B \-t
+has been specified then the times are dumped in the corresponding
+format; otherwise, raw format (\fB \-R\fP) is used.
+.TP
+.B \-R
+Dump the timestamps of the first and last packets in each input file
+as raw timestamps (i.e., in the form \fI sssssssss.uuuuuu\fP).
+.TP
+.B \-r
+Same as
+.B \-R
+except the timestamps are dumped in human-readable format, similar
+to that used by \fI date(1)\fP.
+.TP
+.B \-t
+Same as
+.B \-R
+except the timestamps are dumped in
+.I tcpslice
+format, i.e., in the
+.I ymdhmsu
+format discussed above.
+.TP
+.B \-w
+Direct the output to \fIfile\fR rather than \fIstdout\fP.
+.SH "SEE ALSO"
+tcpdump(l)
+.SH AUTHOR
+Vern Paxson (vern@ee.lbl.gov), of
+Lawrence Berkeley Laboratory, University of California, Berkeley, CA.
+.SH BUGS
+An input filename that beings with a digit or a `+' can be confused
+with a start/end time. Such filenames can be specified with a
+leading `./'; for example, specify the file `04Jul76.trace' as
+`./04Jul76.trace'.
+.LP
+.I tcpslice
+cannot read its input from \fIstdin\fP, since it uses random-access
+to rummage through its input files.
+.LP
+.I tcpslice
+refuses to write to its output if it is a terminal
+(as indicated by \fIisatty(3)\fP). This is not a bug but a feature,
+to prevent it from spraying binary data to the user's terminal.
+Note that this means you must either redirect \fIstdout\fP or specify an
+output file via \fB\-w\fP.
+.LP
+.I tcpslice
+will not work properly on \fItcpdump\fP files spanning more than one year;
+with files containing portions of packets whose original length was
+more than 65,535 bytes; nor with files containing fewer than three packets.
+Such files result in
+the error message: `couldn't find final packet in file'. These problems
+are due to the interpolation scheme used by
+.I tcpslice
+to greatly speed up its processing when dealing with large trace files.
+Note that
+.I tcpslice
+can efficiently extract slices from the middle of trace files of any
+size, and can also work with truncated trace files (i.e., the final packet
+in the file is only partially present, typically due to \fItcpdump\fP
+being ungracefully killed).
diff --git a/usr.sbin/tcpdump/tcpslice/tcpslice.c b/usr.sbin/tcpdump/tcpslice/tcpslice.c
new file mode 100644
index 0000000..b5b6eea
--- /dev/null
+++ b/usr.sbin/tcpdump/tcpslice/tcpslice.c
@@ -0,0 +1,645 @@
+/*
+ * 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: (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) 1987-1990 The Regents of the University of California.\nAll rights reserved.\n";
+static char rcsid[] =
+ "@(#)$Header: tcpslice.c,v 1.10 92/06/02 17:57:44 mccanne Exp $ (LBL)";
+#endif
+
+/*
+ * tcpslice - extract pieces of and/or glue together tcpdump files
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <netinet/in.h>
+#include <varargs.h>
+
+#include "savefile.h"
+#include "version.h"
+
+
+int tflag = 0; /* global that util routines are sensitive to */
+
+char *program_name;
+
+long thiszone; /* gmt to local correction in trace file */
+
+/* Length of saved portion of packet. */
+int snaplen;
+
+/* Length of saved portion of data past link level protocol. */
+int snapdlen;
+
+/* Precision of clock used to generate trace file. */
+int precision;
+
+static int linkinfo;
+
+/* Style in which to print timestamps; RAW is "secs.usecs"; READABLE is
+ * ala the Unix "date" tool; and PARSEABLE is tcpslice's custom format,
+ * designed to be easy to parse. The default is RAW.
+ */
+enum stamp_styles { TIMESTAMP_RAW, TIMESTAMP_READABLE, TIMESTAMP_PARSEABLE };
+enum stamp_styles timestamp_style = TIMESTAMP_RAW;
+
+
+time_t gwtm2secs( /* struct tm *tmp */ );
+
+
+long local_time_zone( /* timestamp */ );
+struct timeval parse_time(/* time_string, base_time*/);
+void fill_tm(/* time_string, is_delta, t, usecs_addr */);
+void get_file_range( /* filename, first_time, last_time */ );
+struct timeval first_packet_time(/* filename */);
+void extract_slice(/* filename, start_time, stop_time */);
+char *timestamp_to_string( /* timestamp */ );
+void dump_times(/* filename */);
+void usage();
+
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int op;
+ int dump_flag = 0;
+ int report_times = 0;
+ char *start_time_string = 0;
+ char *stop_time_string = 0;
+ char *write_file_name = "-"; /* default is stdout */
+ struct timeval first_time, start_time, stop_time;
+
+ extern char *optarg;
+ extern int optind, opterr;
+
+ program_name = argv[0];
+
+ opterr = 0;
+ while ((op = getopt(argc, argv, "dRrtw:")) != EOF)
+ switch (op) {
+
+ case 'd':
+ dump_flag = 1;
+ break;
+
+ case 'R':
+ ++report_times;
+ timestamp_style = TIMESTAMP_RAW;
+ break;
+
+ case 'r':
+ ++report_times;
+ timestamp_style = TIMESTAMP_READABLE;
+ break;
+
+ case 't':
+ ++report_times;
+ timestamp_style = TIMESTAMP_PARSEABLE;
+ break;
+
+ case 'w':
+ write_file_name = optarg;
+ break;
+
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+
+ if ( report_times > 1 )
+ error( "only one of -R, -r, or -t can be specified" );
+
+
+ if (optind < argc)
+ /* See if the next argument looks like a possible
+ * start time, and if so assume it is one.
+ */
+ if (isdigit(argv[optind][0]) || argv[optind][0] == '+')
+ start_time_string = argv[optind++];
+
+ if (optind < argc)
+ if (isdigit(argv[optind][0]) || argv[optind][0] == '+')
+ stop_time_string = argv[optind++];
+
+
+ if (optind >= argc)
+ error("at least one input file must be given");
+
+
+ first_time = first_packet_time(argv[optind]);
+ fclose( sf_readfile );
+
+
+ if (start_time_string)
+ start_time = parse_time(start_time_string, first_time);
+ else
+ start_time = first_time;
+
+ if (stop_time_string)
+ stop_time = parse_time(stop_time_string, start_time);
+
+ else
+ {
+ stop_time = start_time;
+ stop_time.tv_sec += 86400*3660; /* + 10 years; "forever" */
+ }
+
+
+ if (report_times) {
+ for (; optind < argc; ++optind)
+ dump_times(argv[optind]);
+ }
+
+ if (dump_flag) {
+ printf( "start\t%s\nstop\t%s\n",
+ timestamp_to_string( &start_time ),
+ timestamp_to_string( &stop_time ) );
+ }
+
+ if (! report_times && ! dump_flag) {
+ if ( ! strcmp( write_file_name, "-" ) &&
+ isatty( fileno(stdout) ) )
+ error("stdout is a terminal; redirect or use -w");
+
+ sf_write_init(write_file_name, linkinfo, thiszone, snaplen,
+ precision);
+
+ for (; optind < argc; ++optind)
+ extract_slice(argv[optind], &start_time, &stop_time);
+
+ fclose( sf_writefile );
+ }
+
+ return 0;
+}
+
+
+/* Returns non-zero if a string matches the format for a timestamp,
+ * 0 otherwise.
+ */
+int is_timestamp( str )
+char *str;
+ {
+ while ( isdigit(*str) || *str == '.' )
+ ++str;
+
+ return *str == '\0';
+ }
+
+
+/* Return the correction in seconds for the local time zone with respect
+ * to Greenwich time.
+ */
+long local_time_zone(timestamp)
+long timestamp;
+{
+ struct timeval now;
+ struct timezone tz;
+ long localzone;
+
+ if (gettimeofday(&now, &tz) < 0) {
+ perror("tcpslice: gettimeofday");
+ exit(1);
+ }
+ localzone = tz.tz_minuteswest * -60;
+
+ if (localtime((time_t *) &timestamp)->tm_isdst)
+ localzone += 3600;
+
+ return localzone;
+}
+
+/* Given a string specifying a time (or a time offset) and a "base time"
+ * from which to compute offsets and fill in defaults, returns a timeval
+ * containing the specified time.
+ */
+
+struct timeval
+parse_time(time_string, base_time)
+ char *time_string;
+ struct timeval base_time;
+{
+ struct tm *bt = localtime((time_t *) &base_time.tv_sec);
+ struct tm t;
+ struct timeval result;
+ time_t usecs = 0;
+ int is_delta = (time_string[0] == '+');
+
+ if ( is_delta )
+ ++time_string; /* skip over '+' sign */
+
+ if ( is_timestamp( time_string ) )
+ { /* interpret as a raw timestamp or timestamp offset */
+ char *time_ptr;
+
+ result.tv_sec = atoi( time_string );
+ time_ptr = strchr( time_string, '.' );
+
+ if ( time_ptr )
+ { /* microseconds are specified, too */
+ int num_digits = strlen( time_ptr + 1 );
+ result.tv_usec = atoi( time_ptr + 1 );
+
+ /* turn 123.456 into 123 seconds plus 456000 usec */
+ while ( num_digits++ < 6 )
+ result.tv_usec *= 10;
+ }
+
+ else
+ result.tv_usec = 0;
+
+ if ( is_delta )
+ {
+ result.tv_sec += base_time.tv_sec;
+ result.tv_usec += base_time.tv_usec;
+
+ if ( result.tv_usec > 1000000 )
+ {
+ result.tv_usec -= 1000000;
+ ++result.tv_sec;
+ }
+ }
+
+ return result;
+ }
+
+ if (is_delta) {
+ t = *bt;
+ usecs = base_time.tv_usec;
+ } else {
+ /* Zero struct (easy way around lack of tm_gmtoff/tm_zone
+ * under older systems) */
+ bzero((char *)&t, sizeof(t));
+
+ /* Set values to "not set" flag so we can later identify
+ * and default them.
+ */
+ t.tm_sec = t.tm_min = t.tm_hour = t.tm_mday = t.tm_mon =
+ t.tm_year = -1;
+ }
+
+ fill_tm(time_string, is_delta, &t, &usecs);
+
+ /* Now until we reach a field that was specified, fill in the
+ * missing fields from the base time.
+ */
+#define CHECK_FIELD(field_name) \
+ if (t.field_name < 0) \
+ t.field_name = bt->field_name; \
+ else \
+ break
+
+ do { /* bogus do-while loop so "break" in CHECK_FIELD will work */
+ CHECK_FIELD(tm_year);
+ CHECK_FIELD(tm_mon);
+ CHECK_FIELD(tm_mday);
+ CHECK_FIELD(tm_hour);
+ CHECK_FIELD(tm_min);
+ CHECK_FIELD(tm_sec);
+ } while ( 0 );
+
+ /* Set remaining unspecified fields to 0. */
+#define ZERO_FIELD_IF_NOT_SET(field_name,zero_val) \
+ if (t.field_name < 0) \
+ t.field_name = zero_val
+
+ if (! is_delta) {
+ ZERO_FIELD_IF_NOT_SET(tm_year,90); /* should never happen */
+ ZERO_FIELD_IF_NOT_SET(tm_mon,0);
+ ZERO_FIELD_IF_NOT_SET(tm_mday,1);
+ ZERO_FIELD_IF_NOT_SET(tm_hour,0);
+ ZERO_FIELD_IF_NOT_SET(tm_min,0);
+ ZERO_FIELD_IF_NOT_SET(tm_sec,0);
+ }
+
+ result.tv_sec = gwtm2secs(&t);
+ result.tv_sec -= local_time_zone(result.tv_sec);
+ result.tv_usec = usecs;
+
+ return result;
+}
+
+
+/* Fill in (or add to, if is_delta is true) the time values in the
+ * tm struct "t" as specified by the time specified in the string
+ * "time_string". "usecs_addr" is updated with the specified number
+ * of microseconds, if any.
+ */
+void
+fill_tm(time_string, is_delta, t, usecs_addr)
+ char *time_string;
+ int is_delta; /* if true, add times in instead of replacing */
+ struct tm *t; /* tm struct to be filled from time_string */
+ time_t *usecs_addr;
+{
+ char *t_start, *t_stop, format_ch;
+ int val;
+
+#define SET_VAL(lhs,rhs) \
+ if (is_delta) \
+ lhs += rhs; \
+ else \
+ lhs = rhs
+
+ /* Loop through the time string parsing one specification at
+ * a time. Each specification has the form <number><letter>
+ * where <number> indicates the amount of time and <letter>
+ * the units.
+ */
+ for (t_stop = t_start = time_string; *t_start; t_start = ++t_stop) {
+ if (! isdigit(*t_start))
+ error("bad date format %s, problem starting at %s",
+ time_string, t_start);
+
+ while (isdigit(*t_stop))
+ ++t_stop;
+ if (! t_stop)
+ error("bad date format %s, problem starting at %s",
+ time_string, t_start);
+
+ val = atoi(t_start);
+
+ format_ch = *t_stop;
+ if ( isupper( format_ch ) )
+ format_ch = tolower( format_ch );
+
+ switch (format_ch) {
+ case 'y':
+ if ( val > 1900 )
+ val -= 1900;
+ SET_VAL(t->tm_year, val);
+ break;
+
+ case 'm':
+ if (strchr(t_stop+1, 'D') ||
+ strchr(t_stop+1, 'd'))
+ /* it's months */
+ SET_VAL(t->tm_mon, val - 1);
+ else /* it's minutes */
+ SET_VAL(t->tm_min, val);
+ break;
+
+ case 'd':
+ SET_VAL(t->tm_mday, val);
+ break;
+
+ case 'h':
+ SET_VAL(t->tm_hour, val);
+ break;
+
+ case 's':
+ SET_VAL(t->tm_sec, val);
+ break;
+
+ case 'u':
+ SET_VAL(*usecs_addr, val);
+ break;
+
+ default:
+ error(
+ "bad date format %s, problem starting at %s",
+ time_string, t_start);
+ }
+ }
+}
+
+
+/* Return in first_time and last_time the timestamps of the first and
+ * last packets in the given file.
+ */
+void
+get_file_range( filename, first_time, last_time )
+ char filename[];
+ struct timeval *first_time;
+ struct timeval *last_time;
+{
+ *first_time = first_packet_time( filename );
+
+ if ( ! sf_find_end( first_time, last_time ) )
+ error( "couldn't find final packet in file %s", filename );
+}
+
+
+/* Returns the timestamp of the first packet in the given tcpdump save
+ * file, which as a side-effect is initialized for further save-file
+ * reading.
+ */
+
+struct timeval
+first_packet_time(filename)
+ char filename[];
+{
+ struct packet_header hdr;
+ u_char *buf;
+
+ if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision))
+ error( "bad tcpdump file %s", filename );
+
+ buf = (u_char *)malloc((unsigned)snaplen);
+
+ if (sf_next_packet(&hdr, buf, snaplen))
+ error( "bad status reading first packet in %s", filename );
+
+ free((char *)buf);
+
+ return hdr.ts;
+}
+
+
+/* Extract from the given file all packets with timestamps between
+ * the two time values given (inclusive). These packets are written
+ * to the save file output set up by a previous call to sf_write_init().
+ * Upon return, start_time is adjusted to reflect a time just after
+ * that of the last packet written to the output.
+ */
+
+void
+extract_slice(filename, start_time, stop_time)
+ char filename[];
+ struct timeval *start_time;
+ struct timeval *stop_time;
+{
+ long start_pos, stop_pos;
+ struct timeval file_start_time, file_stop_time;
+ int status;
+ struct packet_header hdr;
+ u_char *buf;
+
+
+ if (sf_read_init(filename, &linkinfo, &thiszone, &snaplen, &precision))
+ error( "bad tcpdump file %s", filename );
+
+ buf = (u_char *)malloc((unsigned)snaplen);
+
+ start_pos = ftell( sf_readfile );
+
+
+ if ( (status = sf_next_packet( &hdr, buf, snaplen )) )
+ error( "bad status %d reading packet in %s",
+ status, filename );
+
+ file_start_time = hdr.ts;
+
+
+ if ( ! sf_find_end( &file_start_time, &file_stop_time ) )
+ error( "problems finding end packet of file %s",
+ filename );
+
+ stop_pos = ftell( sf_readfile );
+
+
+ /* sf_find_packet() requires that the time it's passed as its last
+ * argument be in the range [min_time, max_time], so we enforce
+ * that constraint here.
+ */
+ if ( sf_timestamp_less_than( start_time, &file_start_time ) )
+ *start_time = file_start_time;
+
+ if ( sf_timestamp_less_than( &file_stop_time, start_time ) )
+ return; /* there aren't any packets of interest in the file */
+
+
+ sf_find_packet( &file_start_time, start_pos,
+ &file_stop_time, stop_pos,
+ start_time );
+
+ for ( ; ; )
+ {
+ struct timeval *timestamp;
+ status = sf_next_packet( &hdr, buf, snaplen );
+
+ if ( status )
+ {
+ if ( status != SFERR_EOF )
+ error( "bad status %d reading packet in %s",
+ status, filename );
+ break;
+ }
+
+ timestamp = &hdr.ts;
+
+ if ( ! sf_timestamp_less_than( timestamp, start_time ) )
+ { /* packet is recent enough */
+ if ( sf_timestamp_less_than( stop_time, timestamp ) )
+ /* We've gone beyond the end of the region
+ * of interest ... We're done with this file.
+ */
+ break;
+
+ sf_write( buf, timestamp, (int) hdr.len,
+ (int) hdr.caplen );
+ *start_time = *timestamp;
+
+ /* We know that each packet is guaranteed to have
+ * a unique timestamp, so we push forward the
+ * allowed minimum time to weed out duplicate
+ * packets.
+ */
+ ++start_time->tv_usec;
+ }
+ }
+
+ fclose( sf_readfile );
+ free( (char *) buf );
+}
+
+
+/* Translates a timestamp to the time format specified by the user.
+ * Returns a pointer to the translation residing in a static buffer.
+ * There are two such buffers, which are alternated on subseqeuent
+ * calls, so two calls may be made to this routine without worrying
+ * about the results of the first call being overwritten by the
+ * results of the second.
+ */
+
+char *
+timestamp_to_string(timestamp)
+ struct timeval *timestamp;
+{
+ struct tm *t;
+#define NUM_BUFFERS 2
+ static char buffers[NUM_BUFFERS][128];
+ static int buffer_to_use = 0;
+ char *buf;
+
+ buf = buffers[buffer_to_use];
+ buffer_to_use = (buffer_to_use + 1) % NUM_BUFFERS;
+
+ switch ( timestamp_style )
+ {
+ case TIMESTAMP_RAW:
+ sprintf( buf, "%d.%d", timestamp->tv_sec, timestamp->tv_usec );
+ break;
+
+ case TIMESTAMP_READABLE:
+ t = localtime((time_t *) &timestamp->tv_sec);
+ strcpy( buf, asctime( t ) );
+ buf[24] = '\0'; /* nuke final newline */
+ break;
+
+ case TIMESTAMP_PARSEABLE:
+ t = localtime((time_t *) &timestamp->tv_sec);
+ sprintf( buf, "%02dy%02dm%02dd%02dh%02dm%02ds%06du",
+ t->tm_year, t->tm_mon + 1, t->tm_mday, t->tm_hour,
+ t->tm_min, t->tm_sec, timestamp->tv_usec );
+ break;
+
+ }
+
+ return buf;
+}
+
+
+/* Given a tcpdump save filename, reports on the times of the first
+ * and last packets in the file.
+ */
+
+void
+dump_times(filename)
+ char filename[];
+{
+ struct timeval first_time, last_time;
+
+ get_file_range( filename, &first_time, &last_time );
+
+ printf( "%s\t%s\t%s\n",
+ filename,
+ timestamp_to_string( &first_time ),
+ timestamp_to_string( &last_time ) );
+}
+
+void
+usage()
+{
+ (void)fprintf(stderr, "tcpslice for tcpdump version %d.%d\n",
+ VERSION_MAJOR, VERSION_MINOR);
+ (void)fprintf(stderr,
+"Usage: tcpslice [-dRrt] [-w file] [start-time [end-time]] file ... \n");
+
+ exit(-1);
+}
diff --git a/usr.sbin/timed/Makefile b/usr.sbin/timed/Makefile
new file mode 100644
index 0000000..a89ab16
--- /dev/null
+++ b/usr.sbin/timed/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+SUBDIR= timed timedc
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/timed/SMM.doc/timed/Makefile b/usr.sbin/timed/SMM.doc/timed/Makefile
new file mode 100644
index 0000000..22ff6e6
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/12.timed
+SRCS= timed.ms
+MACROS= -ms
+PRINTER=Pdp
+
+paper.${PRINTER}: ${SRCS}
+ ${SOELIM} ${SRCS} | ${TBL} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/timed/SMM.doc/timed/date b/usr.sbin/timed/SMM.doc/timed/date
new file mode 100644
index 0000000..e4e4d58
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/date
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)date 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Seconds of Time to Set
+_
+Microseconds of Time to Set
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/loop b/usr.sbin/timed/SMM.doc/timed/loop
new file mode 100644
index 0000000..11ccb4d
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/loop
@@ -0,0 +1,54 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)loop 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c | c s s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Hop Count ( unused )
+_
+( unused )
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/spell.ok b/usr.sbin/timed/SMM.doc/timed/spell.ok
new file mode 100644
index 0000000..8ecfe15
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/spell.ok
@@ -0,0 +1,34 @@
+ACK
+ADJTIME
+Adjtime
+CS
+CSELT
+Candidature
+DATEACK
+DoD
+Gusella
+MASTERACK
+MASTERREQ
+MASTERUP
+MSITE
+MSITEREQ
+Protocol''SMM:22
+Riccardo
+SETDATE
+SETDATEREQ
+SETTIME
+SLAVEUP
+SMM:22
+Stefano
+TRACEOFF
+TRACEON
+TSP
+Timedc
+UDP
+USENIX
+Zatti
+candidature
+ce
+daemon
+daemons
+timedc
diff --git a/usr.sbin/timed/SMM.doc/timed/time b/usr.sbin/timed/SMM.doc/timed/time
new file mode 100644
index 0000000..619d171
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/time
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)time 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+Seconds of Adjustment
+_
+Microseconds of Adjustment
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timed/timed.ms b/usr.sbin/timed/SMM.doc/timed/timed.ms
new file mode 100644
index 0000000..f5a3b19
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/timed.ms
@@ -0,0 +1,504 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)timed.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+The Berkeley
+.UX
+.br
+Time Synchronization Protocol
+.AU
+Riccardo Gusella, Stefano Zatti, and James M. Bloom
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.FS
+This work was sponsored by the Defense Advanced Research Projects Agency
+(DoD), monitored by the Naval Electronics Systems
+Command under contract No. N00039-84-C-0089, and by the Italian CSELT
+Corporation.
+The views and conclusions contained in this document are those of the
+authors and should not be interpreted as representing official policies,
+either expressed or implied, of the Defense Research Projects Agency,
+of the US Government, or of CSELT.
+.FE
+.LP
+.OH 'The Berkeley UNIX Time Synchronization Protocol''SMM:12-%'
+.EH 'SMM:12-%''The Berkeley UNIX Time Synchronization Protocol'
+.SH
+Introduction
+.PP
+The Time Synchronization Protocol (TSP)
+has been designed for specific use by the program \fItimed\fP,
+a local area network clock synchronizer for
+the UNIX 4.3BSD operating
+system.
+Timed is built on the DARPA UDP protocol [4] and
+is based on a master slave scheme.
+.PP
+TSP serves a dual purpose.
+First, it supports messages for the synchronization of the clocks
+of the various hosts in a local area network.
+Second, it supports messages for the election that occurs
+among slave time daemons when, for any reason, the master disappears.
+The synchronization mechanism and the election procedure
+employed by the program timed are described
+in other documents [1,2,3].
+.PP
+Briefly, the synchronization software, which works in a
+local area network, consists of a collection of \fItime daemons\fP
+(one per machine) and is based on a master-slave
+structure.
+The present implementation keeps processor clocks synchronized
+within 20 milliseconds.
+A \fImaster time daemon\fP measures the time
+difference between the clock of the machine on which it
+is running and those of all other machines. The current implementation
+uses ICMP \fITime Stamp Requests\fP [5] to measure the clock difference
+between machines.
+The master computes the \fInetwork time\fP as the average of the
+times provided by nonfaulty clocks.\**
+.FS
+A clock is considered to be faulty when its value
+is more than a small specified
+interval apart from the majority of the clocks
+of the machines on the same network.
+See [1,2] for more details.
+.FE
+It then sends to each \fIslave time daemon\fP the
+correction that should be performed on the clock of its machine.
+This process is repeated periodically.
+Since the correction is expressed as a time difference rather than an
+absolute time, transmission delays do not interfere with synchronization.
+When a machine comes up and joins the network,
+it starts a slave time daemon, which
+will ask the master for the correct time and will reset the machine's clock
+before any user activity can begin.
+The time daemons therefore maintain a single network time in spite of
+the drift of clocks away from each other.
+.PP
+Additionally, a time daemon on gateway machines may run as
+a \fIsubmaster\fP.
+A submaster time daemon functions as a slave on one network that
+already has a master and as master on other networks.
+In addition, a submaster is responsible for propagating broadcast
+packets from one network to the other.
+.PP
+To ensure that service provided is continuous and reliable,
+it is necessary to implement an election algorithm that will elect a
+new master should the machine running the current master crash, the master
+terminate (for example, because of a run-time error), or the network be
+partitioned.
+Under our algorithm, slaves are able to realize when the master has
+stopped functioning and to elect a new master from among themselves.
+It is important to note that since the failure of the master results
+only in a gradual divergence of clock values, the election
+need not occur immediately.
+.PP
+All the communication occurring among time daemons uses the TSP
+protocol.
+While some messages need not be sent in a reliable way,
+most communication in TSP requires reliability not provided by the underlying
+protocol.
+Reliability is achieved by the use of acknowledgements, sequence numbers, and
+retransmission when message losses occur.
+When a message that requires acknowledgment is not acknowledged after
+multiple attempts,
+the time daemon that has sent the message will assume that the
+addressee is down.
+This document will not describe the details of how reliability is
+implemented, but will only point out when
+a message type requires a reliable transport mechanism.
+.PP
+The message format in TSP is the same for all message types;
+however, in some instances, one or more fields are not used.
+The next section describes the message format.
+The following sections describe
+in detail the different message types, their use and the contents
+of each field. NOTE: The message format is likely to change in
+future versions of timed.
+.sp 2
+.SH
+Message Format
+.PP
+All fields are based upon 8-bit bytes. Fields should be sent in
+network byte order if they are more than one byte long.
+The structure of a TSP message is the following:
+.IP 1)
+A one byte message type.
+.IP 2)
+A one byte version number, specifying the protocol version which the
+message uses.
+.IP 3)
+A two byte sequence number to be used for recognizing duplicate messages
+that occur when messages are retransmitted.
+.IP 4)
+Eight bytes of packet specific data. This field contains two 4 byte time
+values, a one byte hop count, or may be unused depending on the type
+of the packet.
+.IP 5)
+A zero-terminated string of up to 256 \s-2ASCII\s+2 characters with the name of
+the machine sending the message.
+.PP
+The following charts describe the message types,
+show their fields, and explain their usages.
+For the purpose of the following discussion, a time daemon can
+be considered to be in
+one of three states: slave, master, or candidate for election to master.
+Also, the term \fIbroadcast\fP refers to
+the sending of a message to all active time daemons.
+.sp 1
+.DS L
+.SH
+Adjtime Message
+.so time
+.LP
+Type: TSP_ADJTIME (1)
+.sp 1
+.PP
+The master sends this message to a slave to communicate
+the difference between
+the clock of the slave and
+the network time the master has just computed.
+The slave will accordingly
+adjust the time of its machine.
+This message requires an acknowledgment.
+.sp 1
+.DE
+.DS L
+.SH
+Acknowledgment Message
+.so unused
+.LP
+Type: TSP_ACK (2)
+.sp 1
+.PP
+Both the master and the slaves use this message for
+acknowledgment only.
+It is used in several different contexts, for example
+in reply to an Adjtime message.
+.sp 1
+.DE
+.DS L
+.SH
+Master Request Message
+.so unused
+.LP
+Type: TSP_MASTERREQ (3)
+.sp 1
+.PP
+A newly-started time daemon broadcasts this message to
+locate a master. No other action is implied by this packet.
+It requires a Master Acknowledgment.
+.sp 1
+.DE
+.DS L
+.SH
+Master Acknowledgement
+.so unused
+.LP
+Type: TSP_MASTERACK (4)
+.sp 1
+.PP
+The master sends this message to acknowledge the Master Request message
+and the Conflict Resolution Message.
+.sp 1
+.DE
+.DS L
+.SH
+Set Network Time Message
+.so date
+.LP
+Type: TSP_SETTIME (5)
+.sp 1
+.PP
+The master sends this message to slave time daemons to set their time.
+This packet is sent to newly started time daemons and when the network
+date is changed.
+It contains the master's time as an approximation of the network time.
+It requires an acknowledgment.
+The next
+synchronization round will eliminate the small time difference
+caused by the random delay in the communication channel.
+.sp 1
+.DE
+.DS L
+.SH
+Master Active Message
+.so unused
+.LP
+Type: TSP_MASTERUP (6)
+.sp 1
+.PP
+The master broadcasts this message to
+solicit the names of the active slaves.
+Slaves will reply with a Slave Active message.
+.sp 1
+.DE
+.DS L
+.SH
+Slave Active Message
+.so unused
+.LP
+Type: TSP_SLAVEUP (7)
+.sp 1
+.PP
+A slave sends this message to the master in answer to a Master Active message.
+This message is also sent when a new slave starts up to inform the master that
+it wants to be synchronized.
+.sp 1
+.DE
+.DS L
+.SH
+Master Candidature Message
+.so unused
+.LP
+Type: TSP_ELECTION (8)
+.sp 1
+.PP
+A slave eligible to become a master broadcasts this message when its election
+timer expires.
+The message declares that the slave wishes to become the new master.
+.sp 1
+.DE
+.DS L
+.SH
+Candidature Acceptance Message
+.so unused
+.LP
+Type: TSP_ACCEPT (9)
+.sp 1
+.PP
+A slave sends this message to accept the candidature of the time daemon
+that has broadcast an Election message.
+The candidate will add the slave's name to the list of machines that it
+will control should it become the master.
+.sp 1
+.DE
+.DS L
+.SH
+Candidature Rejection Message
+.so unused
+.LP
+Type: TSP_REFUSE (10)
+.sp 1
+.PP
+After a slave accepts the candidature of a time daemon, it will reply
+to any election messages from other slaves
+with this message.
+This rejects any candidature other than the first received.
+.sp 1
+.DE
+.DS L
+.SH
+Multiple Master Notification Message
+.so unused
+.LP
+Type: TSP_CONFLICT (11)
+.sp 1
+.PP
+When two or more masters reply to a Master Request message, the slave
+uses this message to inform one of them that more than one master exists.
+.sp 1
+.DE
+.DS L
+.SH
+Conflict Resolution Message
+.so unused
+.LP
+Type: TSP_RESOLVE (12)
+.sp 1
+.PP
+A master which has been informed of the existence of other masters
+broadcasts this message to determine who the other masters are.
+.sp 1
+.DE
+.DS L
+.SH
+Quit Message
+.so unused
+.LP
+Type: TSP_QUIT (13)
+.sp 1
+.PP
+This message is sent by the master in three different contexts:
+1) to a candidate that broadcasts an Master Candidature message,
+2) to another master when notified of its existence,
+3) to another master if a loop is detected.
+In all cases, the recipient time daemon will become a slave.
+This message requires an acknowledgement.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Message
+.so date
+.LP
+Type: TSP_SETDATE (22)
+.sp 1
+.PP
+The program \fIdate\fP\|(1) sends this message to the local time daemon
+when a super-user wants to set the network date.
+If the local time daemon is the master, it will set the date;
+if it is a slave, it will communicate the desired date to the master.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Request Message
+.so date
+.LP
+Type: TSP_SETDATEREQ (23)
+.sp 1
+.PP
+A slave that has received a Set Date message will communicate the
+desired date to the master using this message.
+.sp 1
+.DE
+.DS L
+.SH
+Set Date Acknowledgment Message
+.so unused
+.LP
+Type: TSP_DATEACK (16)
+.sp 1
+.PP
+The master sends this message to a slave in acknowledgment of a
+Set Date Request Message.
+The same message is sent by the local time daemon to the program
+\fIdate(1)\fP to confirm that the network date has been set by the
+master.
+.sp 1
+.DE
+.DS L
+.SH
+Start Tracing Message
+.so unused
+.LP
+Type: TSP_TRACEON (17)
+.sp 1
+.PP
+The controlling program \fItimedc\fP sends this message to the local
+time daemon to start the recording in a system file of
+all messages received.
+.sp 1
+.DE
+.DS L
+.SH
+Stop Tracing Message
+.so unused
+.LP
+Type: TSP_TRACEOFF (18)
+.sp 1
+.PP
+\fITimedc\fP sends this message to the local
+time daemon to stop the recording of
+messages received.
+.sp 1
+.DE
+.DS L
+.SH
+Master Site Message
+.so unused
+.LP
+Type: TSP_MSITE (19)
+.sp 1
+.PP
+\fITimedc\fP sends this message to the local time daemon to find out
+where the master is running.
+.sp 1
+.DE
+.DS L
+.SH
+Remote Master Site Message
+.so unused
+.LP
+Type: TSP_MSITEREQ (20)
+.sp 1
+.PP
+A local time daemon broadcasts this message to find the location
+of the master.
+It then uses the Acknowledgement message to
+communicate this location to \fItimedc\fP.
+.sp 1
+.DE
+.DS L
+.SH
+Test Message
+.so unused
+.LP
+Type: TSP_TEST (21)
+.sp 1
+.PP
+For testing purposes, \fItimedc\fP sends this message to a slave
+to cause its election timer to expire. NOTE: \fItimed\fP
+is not normally compiled to support this.
+.sp 1
+.DE
+.SH
+.DS L
+.SH
+Loop Detection Message
+.so loop
+.LP
+Type: TSP_LOOP (24)
+.sp 1
+.PP
+This packet is initiated by all masters occasionally to attempt to detect loops.
+All submasters forward this packet onto the networks over which they are master.
+If a master receives a packet it sent out initially,
+it knows that a loop exists and tries to correct the problem.
+.DE
+.SH
+References
+.IP 1.
+R. Gusella and S. Zatti,
+\fITEMPO: A Network Time Controller for Distributed Berkeley UNIX System\fP,
+USENIX Summer Conference Proceedings, Salt Lake City, June 1984.
+.IP 2.
+R. Gusella and S. Zatti, \fIClock Synchronization in a Local Area Network\fP,
+University of California, Berkeley, Technical Report, \fIto appear\fP.
+.IP 3.
+R. Gusella and S. Zatti,
+\fIAn Election Algorithm for a Distributed Clock Synchronization Program\fP,
+University of California, Berkeley, CS Technical Report #275, Dec. 1985.
+.IP 4.
+Postel, J., \fIUser Datagram Protocol\fP, RFC 768.
+Network Information Center, SRI International, Menlo Park, California,
+August 1980.
+.IP 5.
+Postel, J., \fIInternet Control Message Protocol\fP, RFC 792.
+Network Information Center, SRI International, Menlo Park, California,
+September 1981.
diff --git a/usr.sbin/timed/SMM.doc/timed/unused b/usr.sbin/timed/SMM.doc/timed/unused
new file mode 100644
index 0000000..adadfc3
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timed/unused
@@ -0,0 +1,53 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)unused 8.1 (Berkeley) 6/8/93
+.\"
+.ft B
+.TS
+center;
+ce | ce | ce | ce
+| c | c | c | s |
+| c s s s |.
+Byte 1 Byte 2 Byte 3 Byte 4
+=
+Type Version No. Sequence No.
+_
+( unused )
+_
+( unused )
+_
+Machine Name
+_
+\&. . .
+_
+.TE
+.ft R
diff --git a/usr.sbin/timed/SMM.doc/timedop/Makefile b/usr.sbin/timed/SMM.doc/timedop/Makefile
new file mode 100644
index 0000000..ae43850
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timedop/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= smm/11.timedop
+SRCS= timed.ms
+MACROS= -ms
+
+.include <bsd.doc.mk>
diff --git a/usr.sbin/timed/SMM.doc/timedop/timed.ms b/usr.sbin/timed/SMM.doc/timedop/timed.ms
new file mode 100644
index 0000000..feea0b5
--- /dev/null
+++ b/usr.sbin/timed/SMM.doc/timedop/timed.ms
@@ -0,0 +1,279 @@
+.\" Copyright (c) 1986, 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.
+.\"
+.\" @(#)timed.ms 8.1 (Berkeley) 6/8/93
+.\"
+.TL
+Timed Installation and Operation Guide
+.AU
+Riccardo Gusella, Stefano Zatti, James M. Bloom
+.AI
+Computer Systems Research Group
+Computer Science Division
+Department of Electrical Engineering and Computer Science
+University of California, Berkeley
+Berkeley, CA 94720
+.AU
+Kirk Smith
+.AI
+Engineering Computer Network
+Department of Electrical Engineering
+Purdue University
+West Lafayette, IN 47906
+.FS
+This work was sponsored by the Defense Advanced Research Projects Agency
+(DoD), monitored by the Naval Electronics Systems
+Command under contract No. N00039-84-C-0089, and by the CSELT
+Corporation of Italy.
+The views and conclusions contained in this document are those of the
+authors and should not be interpreted as representing official policies,
+either expressed or implied, of the Defense Research Projects Agency,
+of the US Government, or of CSELT.
+.FE
+.LP
+.EH 'SMM:11-%''Timed Installation and Operation'
+.OH 'Timed Installation and Operation''SMM:11-%'
+.SH
+Introduction
+.PP
+The clock synchronization service for
+the UNIX 4.3BSD operating system is composed of a collection of
+time daemons (\fItimed\fP) running on the machines in a local
+area network.
+The algorithms implemented by the service is based on a master-slave scheme.
+The time daemons communicate with each other using the
+\fITime Synchronization Protocol\fP (TSP) which
+is built on the DARPA UDP protocol and described in detail in [4].
+.PP
+A time daemon has a twofold function.
+First, it supports the synchronization of the clocks
+of the various hosts in a local area network.
+Second, it starts (or takes part in) the election that occurs
+among slave time daemons when, for any reason, the master disappears.
+The synchronization mechanism and the election procedure
+employed by the program \fItimed\fP are described
+in other documents [1,2,3].
+The next paragraphs are a brief overview of how the time daemon works.
+This document is mainly concerned with the administrative and technical
+issues of running \fItimed\fP at a particular site.
+.PP
+A \fImaster time daemon\fP measures the time
+differences between the clock of the machine on which it
+is running and those of all other machines.
+The master computes the \fInetwork time\fP as the average of the
+times provided by nonfaulty clocks.\**
+.FS
+A clock is considered to be faulty when its value
+is more than a small specified
+interval apart from the majority of the clocks
+of the other machines [1,2].
+.FE
+It then sends to each \fIslave time daemon\fP the
+correction that should be performed on the clock of its machine.
+This process is repeated periodically.
+Since the correction is expressed as a time difference rather than an
+absolute time, transmission delays do not interfere with
+the accuracy of the synchronization.
+When a machine comes up and joins the network,
+it starts a slave time daemon which
+will ask the master for the correct time and will reset the machine's clock
+before any user activity can begin.
+The time daemons are able to maintain a single network time in spite of
+the drift of clocks away from each other.
+The present implementation keeps processor clocks synchronized
+within 20 milliseconds.
+.PP
+To ensure that the service provided is continuous and reliable,
+it is necessary to implement an election algorithm to elect a
+new master should the machine running the current master crash, the master
+terminate (for example, because of a run-time error), or
+the network be partitioned.
+Under our algorithm, slaves are able to realize when the master has
+stopped functioning and to elect a new master from among themselves.
+It is important to note that, since the failure of the master results
+only in a gradual divergence of clock values, the election
+need not occur immediately.
+.PP
+The machines that are gateways between distinct local area
+networks require particular care.
+A time daemon on such machines may act as a \fIsubmaster\fP.
+This artifact depends on the current inability of
+transmission protocols to broadcast a message on a network
+other than the one to which the broadcasting machine is connected.
+The submaster appears as a slave on one network, and as a master
+on one or more of the other networks to which it is connected.
+.PP
+A submaster classifies each network as one of three types.
+A \fIslave network\fP is a network on which the submaster acts as a slave.
+There can only be one slave network.
+A \fImaster network\fP is a network on which the submaster acts as a master.
+An \fIignored network\fP is any other network which already has a valid master.
+The submaster tries periodically to become master on an ignored
+network, but gives up immediately if a master already exists.
+.SH
+Guidelines
+.PP
+While the synchronization algorithm is quite general, the election
+one, requiring a broadcast mechanism, puts constraints on
+the kind of network on which time daemons can run.
+The time daemon will only work on networks with broadcast capability
+augmented with point-to-point links.
+Machines that are only connected to point-to-point,
+non-broadcast networks may not use the time daemon.
+.PP
+If we exclude submasters, there will normally be, at most, one master time
+daemon in a local area internetwork.
+During an election, only one of the slave time daemons
+will become the new master.
+However, because of the characteristics of its machine,
+a slave can be prevented from becoming the master.
+Therefore, a subset of machines must be designated as potential
+master time daemons.
+A master time daemon will require CPU resources
+proportional to the number of slaves, in general, more than
+a slave time daemon, so it may be advisable to limit master time
+daemons to machines with more powerful processors or lighter loads.
+Also, machines with inaccurate clocks should not be used as masters.
+This is a purely administrative decision: an organization may
+well allow all of its machines to run master time daemons.
+.PP
+At the administrative level, a time daemon on a machine
+with multiple network interfaces, may be told to ignore all
+but one network or to ignore one network.
+This is done with the \fI\-n network\fP and \fI\-i network\fP
+options respectively at start-up time.
+Typically, the time daemon would be instructed to ignore all but
+the networks belonging to the local administrative control.
+.PP
+There are some limitations to the current
+implementation of the time daemon.
+It is expected that these limitations will be removed in future releases.
+The constant NHOSTS in /usr/src/etc/timed/globals.h limits the
+maximum number of machines that may be directly controlled by one
+master time daemon.
+The current maximum is 29 (NHOSTS \- 1).
+The constant must be changed and the program recompiled if a site wishes to
+run \fItimed\fP on a larger (inter)network.
+.PP
+In addition, there is a \fIpathological situation\fP to
+be avoided at all costs, that might occur when
+time daemons run on multiply-connected local area networks.
+In this case, as we have seen, time daemons running on gateway machines
+will be submasters and they will act on some of those
+networks as master time daemons.
+Consider machines A and B that are both gateways between
+networks X and Y.
+If time daemons were started on both A and B without constraints, it would be
+possible for submaster time daemon A to be a slave on network X
+and the master on network Y, while submaster time daemon B is a slave on
+network Y and the master on network X.
+This \fIloop\fP of master time daemons will not function properly
+or guarantee a unique time on both networks, and will cause
+the submasters to use large amounts of system resources in the form
+of network bandwidth and CPU time.
+In fact, this kind of \fIloop\fP can also be generated with more
+than two master time daemons,
+when several local area networks are interconnected.
+.SH
+Installation
+.PP
+In order to start the time daemon on a given machine,
+the following lines should be
+added to the \fIlocal daemons\fP section in the file \fI/etc/rc.local\fP:
+.sp 2
+.in 1i
+.nf
+if [ -f /etc/timed ]; then
+ /etc/timed \fIflags\fP & echo -n ' timed' >/dev/console
+fi
+.fi
+.in -1i
+.sp
+.LP
+In any case, they must appear after the network
+is configured via ifconfig(8).
+.PP
+Also, the file \fI/etc/services\fP should contain the following
+line:
+.sp 2
+.ti 1i
+timed 525/udp timeserver
+.sp
+.LP
+The \fIflags\fP are:
+.IP "-n network" 13
+to consider the named network.
+.IP "-i network"
+to ignore the named network.
+.IP -t
+to place tracing information in \fI/usr/adm/timed.log\fP.
+.IP -M
+to allow this time daemon to become a master.
+A time daemon run without this option will be forced in the state of
+slave during an election.
+.SH
+Daily Operation
+.PP
+\fITimedc(8)\fP is used to control the operation of the time daemon.
+It may be used to:
+.IP \(bu
+measure the differences between machines' clocks,
+.IP \(bu
+find the location where the master \fItimed\fP is running,
+.IP \(bu
+cause election timers on several machines to expire at the same time,
+.IP \(bu
+enable or disable tracing of messages received by \fItimed\fP.
+.LP
+See the manual page on \fItimed\fP\|(8) and \fItimedc\fP\|(8)
+for more detailed information.
+.PP
+The \fIdate(1)\fP command can be used to set the network date.
+In order to set the time on a single machine, the \fI-n\fP flag
+can be given to date(1).
+.bp
+.SH
+References
+.IP 1.
+R. Gusella and S. Zatti,
+\fITEMPO: A Network Time Controller for Distributed Berkeley UNIX System\fP,
+USENIX Summer Conference Proceedings, Salt Lake City, June 1984.
+.IP 2.
+R. Gusella and S. Zatti, \fIClock Synchronization in a Local Area Network\fP,
+University of California, Berkeley, Technical Report, \fIto appear\fP.
+.IP 3.
+R. Gusella and S. Zatti,
+\fIAn Election Algorithm for a Distributed Clock Synchronization Program\fP,
+University of California, Berkeley, CS Technical Report #275, Dec. 1985.
+.IP 4.
+R. Gusella and S. Zatti,
+\fIThe Berkeley UNIX 4.3BSD Time Synchronization Protocol\fP,
+UNIX Programmer's Manual, 4.3 Berkeley Software Distribution, Volume 2c.
diff --git a/usr.sbin/timed/timed/CHANGES b/usr.sbin/timed/timed/CHANGES
new file mode 100644
index 0000000..773f477
--- /dev/null
+++ b/usr.sbin/timed/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/timed/Makefile b/usr.sbin/timed/timed/Makefile
new file mode 100644
index 0000000..7edc521
--- /dev/null
+++ b/usr.sbin/timed/timed/Makefile
@@ -0,0 +1,13 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/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
+MAN8= 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 0000000..c84f52d
--- /dev/null
+++ b/usr.sbin/timed/timed/acksend.c
@@ -0,0 +1,132 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.6 $"
+#endif
+
+#include "globals.h"
+
+struct tsp *answer;
+
+extern u_short sequence;
+
+void
+xmit(type, seq, addr)
+ int type;
+ u_int 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(message, addr, name, ack, net, bad)
+ struct tsp *message; /* this message */
+ struct sockaddr_in *addr; /* to here */
+ char *name;
+ 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 0000000..9cbd665
--- /dev/null
+++ b/usr.sbin/timed/timed/byteorder.c
@@ -0,0 +1,86 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.3 $"
+#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(ptr)
+ 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(ptr)
+ 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 0000000..294eb9b
--- /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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.9 $"
+#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);
+ timevalsub(&wait,&then,&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 0000000..3d15af3
--- /dev/null
+++ b/usr.sbin/timed/timed/cksum.c
@@ -0,0 +1,87 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.3 $"
+#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(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) << 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 0000000..569d2e1
--- /dev/null
+++ b/usr.sbin/timed/timed/correct.c
@@ -0,0 +1,294 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.16 $"
+#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 __P((struct timeval *));
+
+/*
+ * sends to the slaves the corrections for their clocks after fixing our
+ * own
+ */
+void
+correct(avdelta)
+ 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);
+ timevaladd(&to.tsp_time, &adjlocal);
+ 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(corr)
+ 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);
+ timevaladd(&now, corr);
+ 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(msg, now)
+ struct tsp *msg;
+ struct timeval *now;
+{
+ msg->tsp_time.tv_sec += (now->tv_sec - from_when.tv_sec);
+ msg->tsp_time.tv_usec += (now->tv_usec - from_when.tv_usec);
+
+ while (msg->tsp_time.tv_usec < 0) {
+ msg->tsp_time.tv_sec--;
+ msg->tsp_time.tv_usec += 1000000;
+ }
+ while (msg->tsp_time.tv_usec >= 1000000) {
+ msg->tsp_time.tv_sec++;
+ msg->tsp_time.tv_usec -= 1000000;
+ }
+}
diff --git a/usr.sbin/timed/timed/extern.h b/usr.sbin/timed/timed/extern.h
new file mode 100644
index 0000000..09dfaaa
--- /dev/null
+++ b/usr.sbin/timed/timed/extern.h
@@ -0,0 +1,89 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93
+ */
+
+struct hosttbl;
+struct netinfo;
+struct sockaddr_in;
+struct timeval;
+struct tsp;
+
+struct hosttbl *addmach __P((char *, struct sockaddr_in *, struct netinfo *));
+struct hosttbl *findhost __P((char *));
+struct hosttbl *remmach __P((struct hosttbl *));
+
+struct tsp *readmsg __P((int,
+ char *, struct timeval *, struct netinfo *));
+struct tsp *acksend __P((struct tsp *,
+ struct sockaddr_in *, char *, int, struct netinfo *, int));
+
+void addnetname __P((char *));
+void adj_msg_time __P((struct tsp *, struct timeval *));
+void bytehostorder __P((struct tsp *));
+void bytenetorder __P((struct tsp *));
+void byteorder __P((struct tsp *));
+long casual __P((long, long));
+int cksum __P((u_short *, int));
+void correct __P((long));
+char *date __P((void));
+void doquit __P((struct tsp *));
+int election __P((struct netinfo *));
+void get_goodgroup __P((int));
+int good_host_name __P((char *));
+void ignoreack __P((void));
+int in_cksum __P((u_short *, int));
+void lookformaster __P((struct netinfo *));
+void makeslave __P((struct netinfo *));
+int master __P((void));
+void masterack __P((void));
+void masterup __P((struct netinfo *));
+int measure __P((u_long, u_long, char *, struct sockaddr_in *, int));
+void msterup __P((struct netinfo *));
+void mstotvround __P((struct timeval *, long));
+long networkdelta __P((void));
+void newslave __P((struct tsp *));
+void print __P((struct tsp *, struct sockaddr_in *));
+void prthp __P((clock_t));
+void rmnetmachs __P((struct netinfo *));
+void setstatus __P((void));
+int slave __P((void));
+void slaveack __P((void));
+void spreadtime __P((void));
+void suppress __P((struct sockaddr_in *, char *, struct netinfo *));
+void synch __P((long));
+void timevaladd __P((struct timeval *, struct timeval *));
+void timevalsub __P((struct timeval *, struct timeval *, struct timeval *));
+void traceoff __P((char *));
+void traceon __P((void));
+void xmit __P((int, u_int, struct sockaddr_in *));
diff --git a/usr.sbin/timed/timed/globals.h b/usr.sbin/timed/timed/globals.h
new file mode 100644
index 0000000..92aed3e
--- /dev/null
+++ b/usr.sbin/timed/timed/globals.h
@@ -0,0 +1,186 @@
+/*-
+ * 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.
+ *
+ * @(#)globals.h 8.1 (Berkeley) 6/6/93
+ */
+
+#ifdef sgi
+#ident "$Revision: 1.15 $"
+#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 "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 0000000..3397173
--- /dev/null
+++ b/usr.sbin/timed/timed/master.c
@@ -0,0 +1,907 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.21 $"
+#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>
+#endif /* sgi */
+#include <utmp.h>
+#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 __P((struct tsp *));
+
+#ifdef sgi
+extern void logwtmp __P((struct timeval *, struct timeval *));
+#else
+extern void logwtmp __P((char *, char *, char *));
+#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;
+ 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
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#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
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#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(msg)
+ 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);
+
+ timevalsub(&ntime, &msg->tsp_time, &otime);
+ 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(mydelta)
+ 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);
+ timevalsub(&stop, &stop, &check);
+ 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(delta)
+ 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(name)
+ 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(name, addr, ntp)
+ 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(htp)
+ 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(ntp)
+ 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(net)
+ 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(msg)
+ 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(msg)
+ 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()
+{
+ 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(msg)
+ 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(otime, ntime)
+ struct timeval *otime, *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;
+ 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);
+ }
+}
+#endif /* sgi */
diff --git a/usr.sbin/timed/timed/measure.c b/usr.sbin/timed/timed/measure.c
new file mode 100644
index 0000000..4066d10
--- /dev/null
+++ b/usr.sbin/timed/timed/measure.c
@@ -0,0 +1,353 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.8 $"
+#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;
+
+static n_short seqno = 0;
+
+/*
+ * Measures the differences between machines' clocks using
+ * ICMP timestamp messages.
+ */
+int /* status val defined in globals.h */
+measure(maxmsec, wmsec, hname, addr, print)
+ 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);
+ timevaladd(&tdone, &tout); /* 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 = ((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;
+
+ ttrans = tcur;
+ timevaladd(&ttrans, &twait);
+ } else {
+ ttrans = tdone;
+ }
+
+ while (rcvcount < trials) {
+ timevalsub(&tout, &ttrans, &tcur);
+ 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(res, x)
+ 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--;
+ }
+}
+
+void
+timevaladd(tv1, tv2)
+ struct timeval *tv1, *tv2;
+{
+ tv1->tv_sec += tv2->tv_sec;
+ tv1->tv_usec += tv2->tv_usec;
+ if (tv1->tv_usec >= 1000000) {
+ tv1->tv_sec++;
+ tv1->tv_usec -= 1000000;
+ }
+ if (tv1->tv_usec < 0) {
+ tv1->tv_sec--;
+ tv1->tv_usec += 1000000;
+ }
+}
+
+void
+timevalsub(res, tv1, tv2)
+ struct timeval *res, *tv1, *tv2;
+{
+ res->tv_sec = tv1->tv_sec - tv2->tv_sec;
+ res->tv_usec = tv1->tv_usec - tv2->tv_usec;
+ if (res->tv_usec >= 1000000) {
+ res->tv_sec++;
+ res->tv_usec -= 1000000;
+ }
+ if (res->tv_usec < 0) {
+ res->tv_sec--;
+ res->tv_usec += 1000000;
+ }
+}
diff --git a/usr.sbin/timed/timed/networkdelta.c b/usr.sbin/timed/timed/networkdelta.c
new file mode 100644
index 0000000..d64640a
--- /dev/null
+++ b/usr.sbin/timed/timed/networkdelta.c
@@ -0,0 +1,264 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.4 $"
+#endif
+
+#include "globals.h"
+
+static long median __P((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(a, eps_ptr, x, xlim, gnuf)
+ float a; /* initial guess for the median */
+ float *eps_ptr; /* spacing near the median */
+ long *x, *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 0000000..ae5e1c5
--- /dev/null
+++ b/usr.sbin/timed/timed/pathnames.h
@@ -0,0 +1,44 @@
+/*-
+ * 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.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#include <paths.h>
+
+#ifdef sgi
+#define _PATH_MASTERLOG "/usr/adm/timed.masterlog"
+#define _PATH_TIMEDLOG "/usr/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 0000000..3e8f4d2
--- /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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.17 $"
+#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(type, machfrom, intvl, netfrom)
+ 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);
+ timevaladd(&rtout, intvl);
+ FD_ZERO(&ready);
+ for (;;) {
+ (void)gettimeofday(&rtime, 0);
+ timevalsub(&rwait, &rtout, &rtime);
+ 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];
+ 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
+ strncpy(tm, ctime(&msg->tsp_time.tv_sec)+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 0000000..3bb6d85
--- /dev/null
+++ b/usr.sbin/timed/timed/slave.c
@@ -0,0 +1,715 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.20 $"
+#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 __P((struct tsp *, char *));
+static void setmaster __P((struct tsp *));
+static void answerdelay __P((void));
+
+#ifdef sgi
+extern void logwtmp __P((struct timeval *, struct timeval *));
+#else
+extern void logwtmp __P((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;
+ 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());
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#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);
+ timevalsub(&ntime, &msg->tsp_time, &otime);
+ 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
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#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
+ (void)strcpy(newdate, ctime(&msg->tsp_time.tv_sec));
+#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(msg)
+ 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(msg, newdate)
+ 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()
+{
+#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.8 b/usr.sbin/timed/timed/timed.8
new file mode 100644
index 0000000..8f8798d
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.8
@@ -0,0 +1,219 @@
+.\" 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.
+.\"
+.\" @(#)timed.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 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 8 .
+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 8
+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 "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 WARNING
+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
+"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 0000000..b8f7dc7
--- /dev/null
+++ b/usr.sbin/timed/timed/timed.c
@@ -0,0 +1,980 @@
+/*-
+ * 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 copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.25 $"
+#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 __P((void));
+static void pickslavenet __P((struct netinfo *));
+static void add_good_host __P((char *, int));
+
+#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(argc, argv)
+ 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;
+ timetrim_st = fopen(timetrim_fn, "r+");
+ if (0 == timetrim_st) {
+ 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_adj = adj;
+ tot_ticks -= ticks;
+ }
+ }
+ (void)fclose(timetrim_st);
+ }
+ break;
+#endif /* sgi */
+
+ default:
+ fprintf(stderr, USAGE);
+ exit(1);
+ break;
+ }
+ }
+ if (optind < argc) {
+ fprintf(stderr, USAGE);
+ exit(1);
+ }
+
+ /* 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;
+ 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(addr, name,net)
+ 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(ntp)
+ 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(net)
+ 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()
+{
+ 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(ntp)
+ 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(inf, sup)
+ long inf, 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;
+
+ (void)gettimeofday(&tv, (struct timezone *)0);
+ return (ctime(&tv.tv_sec));
+#endif /* sgi */
+}
+
+void
+addnetname(name)
+ 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(name, perm)
+ char *name;
+ int 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(force)
+ 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 0000000..582ea96
--- /dev/null
+++ b/usr.sbin/timed/timedc/Makefile
@@ -0,0 +1,11 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= timedc
+SRCS= cmds.c cmdtab.c timedc.c byteorder.c measure.c cksum.c
+MAN8= 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 0000000..9e0aa21
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmds.c
@@ -0,0 +1,526 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.10 $"
+#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 (2208988800UL) /* seconds before UNIX epoch */
+
+
+/* compute the difference between our date and another machine
+ */
+static int /* difference in days from our time */
+daydiff(hostname)
+ 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(argc, argv)
+ 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(argc, argv)
+ 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(argc, argv)
+ 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 0000000..ad5bbb6
--- /dev/null
+++ b/usr.sbin/timed/timedc/cmdtab.c
@@ -0,0 +1,57 @@
+/*
+ * 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 "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/extern.h b/usr.sbin/timed/timedc/extern.h
new file mode 100644
index 0000000..7f33362
--- /dev/null
+++ b/usr.sbin/timed/timedc/extern.h
@@ -0,0 +1,52 @@
+/*-
+ * 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 8.1 (Berkeley) 6/6/93
+ */
+
+#if __STDC__
+struct tsp;
+#endif
+
+extern struct cmd cmdtab[];
+
+void bytehostorder __P((struct tsp *));
+void bytenetorder __P((struct tsp *));
+void clockdiff __P((int, char *[]));
+void help __P((int, char *[]));
+void intr __P((int));
+void makeargv __P((void));
+void msite __P((int, char *[]));
+int priv_resources __P((void));
+void quit __P((void));
+void testing __P((int, char *[]));
+void tracing __P((int, char *[]));
diff --git a/usr.sbin/timed/timedc/timedc.8 b/usr.sbin/timed/timedc/timedc.8
new file mode 100644
index 0000000..fd495e7
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.8
@@ -0,0 +1,145 @@
+.\" 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.
+.\"
+.\" @(#)timedc.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 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 "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 0000000..02d086a
--- /dev/null
+++ b/usr.sbin/timed/timedc/timedc.c
@@ -0,0 +1,261 @@
+/*-
+ * 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 copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#ifdef sgi
+#ident "$Revision: 1.6 $"
+#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 __P((char *));
+
+int
+main(argc, argv)
+ 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(name)
+ char *name;
+{
+ register char *p, *q;
+ register struct cmd *c, *found;
+ register int nmatches, longest;
+ 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;
+
+ 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 0000000..6771680
--- /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 8.1 (Berkeley) 6/6/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 "extern.h"
diff --git a/usr.sbin/traceroute/Makefile b/usr.sbin/traceroute/Makefile
new file mode 100644
index 0000000..7bbc57b
--- /dev/null
+++ b/usr.sbin/traceroute/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= traceroute
+MAN8= traceroute.8
+BINOWN= root
+BINMODE=4555
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/traceroute/README b/usr.sbin/traceroute/README
new file mode 100644
index 0000000..6d33c6c
--- /dev/null
+++ b/usr.sbin/traceroute/README
@@ -0,0 +1,126 @@
+Tue Dec 27 06:24:24 PST 1988
+
+Traceroute is a system administrators utility to trace the route
+ip packets from the current system take in getting to some
+destination system. See the comments at the front of the
+program for a description of its use.
+
+This program
+
+ a) can only be run by root (it uses raw ip sockets).
+
+ b) REQUIRES A KERNEL MOD to the raw ip output code to run.
+
+If you want to hack on your kernel, my modified version of the
+routine rip_output (in file /sys/netinet/raw_ip.c) is attached.
+This code may or may not resemble the code in your kernel.
+It may offer you a place to start but I make no promises.
+If you do hack your kernel, remember to test everything that uses
+raw ip sockets (e.g., ping and egpup/gated) & make sure they still
+work. I wish you the best of luck and you're on your own.
+
+If your system has the ttl bug mentioned in the source, you
+might want to fix it while you're in the kernel. (This bug
+appears in all releases of BSD up to but not including 4.3tahoe.
+If your version of netinet/ip_icmp.c is any earlier than 7.3
+(April, '87), it has the bug.) The fix is just to add the line
+ ip->ip_ttl = MAXTTL;
+after the line
+ ip->ip_src = t;
+(or anywhere before the call to icmp_send) in routine icmp_reflect.
+
+If you're running this on a pre-4.3bsd system (e.g., Sun 3.x,
+Ultrix) that strips ip headers from icmp messages, add -DARCHAIC
+to CFLAGS in the Makefile. Also note that rip_output contains
+a conditional for a 4.2/4.3 change in the location of a raw
+socket's protocol number. I've checked this under 4.3 & Sun OS
+3.5 but you should double-check your system to make sure the
+appropriate branch of the #if is taken (check the line that
+assigned to ip->ip_p in your system's original rip_output).
+
+A couple of awk programs to massage the traceroute output are
+included. "mean.awk" and "median.awk" compute the mean and median
+time to each hop, respectively. I've found that something like
+
+ traceroute -q 7 foo.somewhere >t
+ awk -f median.awk t | graph
+
+can give you a quick picture of the bad spots on a long
+path (median is usually a better noise filter than mean).
+
+Enjoy.
+
+ - Van Jacobson (van@helios.ee.lbl.gov)
+
+-------------------- rip_output from /sys/netinet/raw_ip.c
+rip_output(m, so)
+ register struct mbuf *m;
+ struct socket *so;
+{
+ register struct ip *ip;
+ int error;
+ struct rawcb *rp = sotorawcb(so);
+ struct sockaddr_in *sin;
+#if BSD>=43
+ short proto = rp->rcb_proto.sp_protocol;
+#else
+ short proto = so->so_proto->pr_protocol;
+#endif
+ /*
+ * if the protocol is IPPROTO_RAW, the user handed us a
+ * complete IP packet. Otherwise, allocate an mbuf for a
+ * header and fill it in as needed.
+ */
+ if (proto != IPPROTO_RAW) {
+ /*
+ * Calculate data length and get an mbuf
+ * for IP header.
+ */
+ int len = 0;
+ struct mbuf *m0;
+
+ for (m0 = m; m; m = m->m_next)
+ len += m->m_len;
+
+ m = m_get(M_DONTWAIT, MT_HEADER);
+ if (m == 0) {
+ m = m0;
+ error = ENOBUFS;
+ goto bad;
+ }
+ m->m_off = MMAXOFF - sizeof(struct ip);
+ m->m_len = sizeof(struct ip);
+ m->m_next = m0;
+
+ ip = mtod(m, struct ip *);
+ ip->ip_tos = 0;
+ ip->ip_off = 0;
+ ip->ip_p = proto;
+ ip->ip_len = sizeof(struct ip) + len;
+ ip->ip_ttl = MAXTTL;
+ } else
+ ip = mtod(m, struct ip *);
+
+ if (rp->rcb_flags & RAW_LADDR) {
+ sin = (struct sockaddr_in *)&rp->rcb_laddr;
+ if (sin->sin_family != AF_INET) {
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+ ip->ip_src.s_addr = sin->sin_addr.s_addr;
+ } else
+ ip->ip_src.s_addr = 0;
+
+ ip->ip_dst = ((struct sockaddr_in *)&rp->rcb_faddr)->sin_addr;
+
+#if BSD>=43
+ return (ip_output(m, rp->rcb_options, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#else
+ return (ip_output(m, (struct mbuf *)0, &rp->rcb_route,
+ (so->so_options & SO_DONTROUTE) | IP_ALLOWBROADCAST));
+#endif
+bad:
+ m_freem(m);
+ return (error);
+}
diff --git a/usr.sbin/traceroute/mean.awk b/usr.sbin/traceroute/mean.awk
new file mode 100644
index 0000000..e97a56f
--- /dev/null
+++ b/usr.sbin/traceroute/mean.awk
@@ -0,0 +1,50 @@
+#!/bin/awk -f
+#
+# 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 0000000..1a8d81d
--- /dev/null
+++ b/usr.sbin/traceroute/median.awk
@@ -0,0 +1,67 @@
+#!/bin/awk -f
+#
+# 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 0000000..c1e13bb
--- /dev/null
+++ b/usr.sbin/traceroute/traceroute.8
@@ -0,0 +1,336 @@
+.\" 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 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 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
+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 0000000..14849fd
--- /dev/null
+++ b/usr.sbin/traceroute/traceroute.c
@@ -0,0 +1,835 @@
+/*-
+ * 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
+static char sccsid[] = "@(#)traceroute.c 8.1 (Berkeley) 6/6/93";
+#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/udp.h>
+
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAXPACKET 65535 /* max ip packet size */
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 64
+#endif
+
+#ifndef FD_SET
+#define NFDBITS (8*sizeof(fd_set))
+#define FD_SETSIZE NFDBITS
+#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 Fprintf (void)fprintf
+#define Sprintf (void)sprintf
+#define Printf (void)printf
+
+/*
+ * format of a (udp) probe packet.
+ */
+struct opacket {
+ struct ip ip;
+ struct udphdr udp;
+ u_char seq; /* sequence number of this packet */
+ u_char ttl; /* ttl packet left with */
+ struct timeval tv; /* time packet left */
+};
+
+u_char packet[512]; /* last inbound (icmp) packet */
+struct opacket *outpacket; /* last output (udp) packet */
+
+int wait_for_reply __P((int, struct sockaddr_in *));
+void send_probe __P((int, int));
+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 *));
+void tvsub __P((struct timeval *, struct timeval *));
+char *inetname __P((struct in_addr));
+void usage __P(());
+
+int s; /* receive (icmp) socket file descriptor */
+int sndsock; /* send (udp) socket file descriptor */
+struct timezone tz; /* leftover */
+
+struct sockaddr whereto; /* Who to try to reach */
+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
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ struct hostent *hp;
+ struct protoent *pe;
+ struct sockaddr_in from, *to;
+ int ch, i, on, probe, seq, tos, ttl;
+
+ on = 1;
+ seq = tos = 0;
+ to = (struct sockaddr_in *)&whereto;
+ while ((ch = getopt(argc, argv, "dm:np:q:rs:t:w:v")) != EOF)
+ switch(ch) {
+ case 'd':
+ options |= SO_DEBUG;
+ break;
+ case 'm':
+ max_ttl = atoi(optarg);
+ if (max_ttl <= 1) {
+ Fprintf(stderr,
+ "traceroute: max ttl must be >1.\n");
+ exit(1);
+ }
+ break;
+ case 'n':
+ nflag++;
+ break;
+ case 'p':
+ port = atoi(optarg);
+ if (port < 1) {
+ Fprintf(stderr,
+ "traceroute: port must be >0.\n");
+ exit(1);
+ }
+ break;
+ case 'q':
+ nprobes = atoi(optarg);
+ if (nprobes < 1) {
+ Fprintf(stderr,
+ "traceroute: nprobes must be >0.\n");
+ exit(1);
+ }
+ 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) {
+ Fprintf(stderr,
+ "traceroute: tos must be 0 to 255.\n");
+ exit(1);
+ }
+ break;
+ case 'v':
+ verbose++;
+ break;
+ case 'w':
+ waittime = atoi(optarg);
+ if (waittime <= 1) {
+ Fprintf(stderr,
+ "traceroute: wait must be >1 sec.\n");
+ exit(1);
+ }
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1)
+ usage();
+
+ setlinebuf (stdout);
+
+ (void) bzero((char *)&whereto, sizeof(struct sockaddr));
+ to->sin_family = AF_INET;
+ to->sin_addr.s_addr = inet_addr(*argv);
+ if (to->sin_addr.s_addr != -1)
+ hostname = *argv;
+ else {
+ hp = gethostbyname(*argv);
+ if (hp) {
+ to->sin_family = hp->h_addrtype;
+ bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);
+ hostname = hp->h_name;
+ } else {
+ (void)fprintf(stderr,
+ "traceroute: unknown host %s\n", *argv);
+ exit(1);
+ }
+ }
+ if (*++argv)
+ datalen = atoi(*argv);
+ if (datalen < 0 || datalen >= MAXPACKET - sizeof(struct opacket)) {
+ Fprintf(stderr,
+ "traceroute: packet size must be 0 <= s < %ld.\n",
+ MAXPACKET - sizeof(struct opacket));
+ exit(1);
+ }
+ datalen += sizeof(struct opacket);
+ outpacket = (struct opacket *)malloc((unsigned)datalen);
+ if (! outpacket) {
+ perror("traceroute: malloc");
+ exit(1);
+ }
+ (void) bzero((char *)outpacket, datalen);
+ outpacket->ip.ip_dst = to->sin_addr;
+ outpacket->ip.ip_tos = tos;
+ outpacket->ip.ip_v = IPVERSION;
+ outpacket->ip.ip_id = 0;
+
+ 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) {
+ perror("traceroute: icmp socket");
+ exit(5);
+ }
+ 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) {
+ perror("traceroute: raw socket");
+ exit(5);
+ }
+#ifdef SO_SNDBUF
+ if (setsockopt(sndsock, SOL_SOCKET, SO_SNDBUF, (char *)&datalen,
+ sizeof(datalen)) < 0) {
+ perror("traceroute: SO_SNDBUF");
+ exit(6);
+ }
+#endif SO_SNDBUF
+#ifdef IP_HDRINCL
+ if (setsockopt(sndsock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
+ sizeof(on)) < 0) {
+ perror("traceroute: IP_HDRINCL");
+ exit(6);
+ }
+#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) bzero((char *)&from, sizeof(struct sockaddr));
+ from.sin_family = AF_INET;
+ from.sin_addr.s_addr = inet_addr(source);
+ if (from.sin_addr.s_addr == -1) {
+ Printf("traceroute: unknown host %s\n", source);
+ exit(1);
+ }
+ outpacket->ip.ip_src = from.sin_addr;
+#ifndef IP_HDRINCL
+ if (bind(sndsock, (struct sockaddr *)&from, sizeof(from)) < 0) {
+ perror ("traceroute: bind:");
+ exit (1);
+ }
+#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;
+ struct ip *ip;
+
+ (void) gettimeofday(&t1, &tz);
+ send_probe(++seq, ttl);
+ 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(" %.3f 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-1)
+ 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
+send_probe(seq, ttl)
+ int seq, ttl;
+{
+ struct opacket *op = outpacket;
+ struct ip *ip = &op->ip;
+ struct udphdr *up = &op->udp;
+ int i;
+
+ ip->ip_off = 0;
+ ip->ip_hl = sizeof(*ip) >> 2;
+ ip->ip_p = IPPROTO_UDP;
+ ip->ip_len = datalen;
+ ip->ip_ttl = ttl;
+ ip->ip_v = IPVERSION;
+ 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)));
+ up->uh_sum = 0;
+
+ op->seq = seq;
+ op->ttl = ttl;
+ (void) gettimeofday(&op->tv, &tz);
+
+ i = sendto(sndsock, (char *)outpacket, datalen, 0, &whereto,
+ sizeof(struct sockaddr));
+ 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
+
+/*
+ * Subtract 2 timeval structs: out = out - in.
+ * Out is assumed to be >= in.
+ */
+void
+tvsub(out, in)
+ register struct timeval *out, *in;
+{
+ if ((out->tv_usec -= in->tv_usec) < 0) {
+ out->tv_sec--;
+ out->tv_usec += 1000000;
+ }
+ out->tv_sec -= in->tv_sec;
+}
+
+
+/*
+ * 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 [-dnrv] [-m max_ttl] [-p port#] [-q nqueries]\n\t\
+[-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 0000000..19b41da
--- /dev/null
+++ b/usr.sbin/trpt/Makefile
@@ -0,0 +1,8 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= trpt
+MAN8= 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 0000000..eee7dc8
--- /dev/null
+++ b/usr.sbin/trpt/trpt.8
@@ -0,0 +1,151 @@
+.\" 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.
+.\"
+.\" @(#)trpt.8 8.2 (Berkeley) 12/11/93
+.\"
+.Dd December 11, 1993
+.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.
+.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 /kernel
+.It Pa /dev/kmem
+.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 0000000..ef18570
--- /dev/null
+++ b/usr.sbin/trpt/trpt.c
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 1983, 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) 1983, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)trpt.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.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;
+ }
+ /*
+ * Discard setgid privileges if not the running kernel so that
+ * bad guys can't print interesting stuff from kernel memory.
+ */
+ setgid(getgid());
+ }
+ else
+ system = (char *)getbootfile();
+
+ 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("%x", (int)tcp_pcbs[i]);
+ if (++i == npcbs)
+ break;
+ fputs(", ", stdout);
+ }
+ putchar('\n');
+ }
+ else for (i = 0; i < npcbs; i++) {
+ printf("\n%x:\n", (int)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 0000000..2d0bcea
--- /dev/null
+++ b/usr.sbin/trsp/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= trsp
+MAN8= 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 0000000..dd8db27
--- /dev/null
+++ b/usr.sbin/trsp/trsp.8
@@ -0,0 +1,141 @@
+.\" 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.
+.\"
+.\" @(#)trsp.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd June 6, 1993
+.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 /kernel
+.It Pa /dev/kmem
+.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 0000000..7548c58
--- /dev/null
+++ b/usr.sbin/trsp/trsp.c
@@ -0,0 +1,433 @@
+/*
+ * 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 copyright[] =
+"@(#) Copyright (c) 1985, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)trsp.c 8.1 (Berkeley) 6/6/93";
+#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 = (char *)getbootfile();
+ 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++;
+ /*
+ * Discard setgid privileges if not the running kernel so that
+ * bad guys can't print interesting stuff from kernel memory.
+ */
+ setgid(getgid());
+ }
+ if (argc > 0) {
+ core = *argv;
+ argc--, argv++;
+ mask++;
+ setgid(getgid());
+ }
+ (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/tzsetup/Makefile b/usr.sbin/tzsetup/Makefile
new file mode 100644
index 0000000..6959dcb
--- /dev/null
+++ b/usr.sbin/tzsetup/Makefile
@@ -0,0 +1,12 @@
+# $Id$
+
+NOPROG= tzsetup
+NOMAN=
+
+all depend:
+
+beforeinstall:
+ $(INSTALL) -c -m $(BINMODE) -o $(BINOWN) -g $(BINGRP) \
+ ${.CURDIR}/tzsetup.sh ${DESTDIR}${BINDIR}/tzsetup
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/tzsetup/tzsetup.sh b/usr.sbin/tzsetup/tzsetup.sh
new file mode 100644
index 0000000..8b71091
--- /dev/null
+++ b/usr.sbin/tzsetup/tzsetup.sh
@@ -0,0 +1,181 @@
+#!/bin/sh
+# $Id: tzsetup.sh,v 1.1 1994/09/13 23:01:59 wollman Exp $
+#
+# Copyright 1994, Garrett A. Wollman. All rights reserved.
+# This script is subject to the terms and conditions listed at the
+# end.
+#
+
+ask() {
+ while true; do
+ echo -n "$1" "(${2-no default}) "
+ read ans
+ if [ -z "$ans" ]; then
+ ans="$2"
+ fi
+ if [ -z "$ans" ]; then
+ echo 'An empty response is not valid.'
+ continue
+ fi
+ return 0
+ done
+}
+
+askyn() {
+ while : ; do
+ ask "$1 [yn]?" $2
+ case $ans in
+ [Yy]*) return 0;;
+ [Nn]*) return 1;;
+ esac
+ done
+}
+
+select() {
+ where=$1
+ while true; do
+ echo "Please select a location from the following list which"
+ echo "has the same legal time as your location:"
+ echo ""
+ ls -C /usr/share/zoneinfo/$where
+ echo ""
+ echo "Type \`\`exit'' to return to the main menu."
+ ask "Your choice:" exit
+ if [ "$ans" = "exit" ]; then return 0; fi
+ city="$ans"
+ if [ -r /usr/share/zoneinfo/$where/$city ]; then
+ echo -n "I think the time in `echo $city | tr _ ' '` is: "
+ TZ=$where/$city date
+ if askyn "Is this what you wanted" y; then
+ rm -f /etc/localtime
+ cp /usr/share/zoneinfo/$where/$city \
+ /etc/localtime && echo "Timezone changed."
+ return 0
+ fi
+ fi
+ done
+}
+
+setadjkerntz() {
+ cat << EOF
+
+You can configure your system to assume that the battery-backed CMOS
+clock is set to your local legal time rather than Universal or
+Greenwich time. When the system boots, the \`adjkerntz' program will
+examine your current time, reverse-apply the timezone correction, and
+then set the system's UTC time to the corrected value. This approach
+is NOT guaranteed to always work; in particular, if you reboot your
+system during the transition from or to summer time, the calculation
+is sometimes impossible, and wierd things may result.
+
+For this reason, we recommend that, unless you absolutely positively
+must leave your CMOS clock on local time, you set your CMOS clock to GMT.
+
+EOF
+ if [ -f /etc/wall_cmos_clock ]; then
+ curr=y
+ echo "This system is currently set up for local CMOS time."
+ else
+ curr=n
+ echo "This system is currently set up for GMT CMOS time."
+ fi
+ if askyn "Do you want a local CMOS clock" $curr; then
+ touch /etc/wall_cmos_clock
+ if [ $curr = "n" ] && askyn "Start now" y; then
+ adjkerntz -i
+ fi
+ else
+ rm -f /etc/wall_cmos_clock
+ fi
+ echo "Done."
+}
+
+mainmenu() {
+ set `TZ= date`
+ if askyn "Is $4, $1 $2 $3 $6 the correct current date and time" n; then
+ cat << EOF
+
+Unless your local time is GMT, this probably means that your CMOS
+clock is on local time. In this case, the local times that you will
+be shown will be incorrect. You should either set your CMOS clock to
+GMT, or select option 98 from the main menu after selecting a
+timezone.
+
+EOF
+ echo -n "Press return to continue ==>"
+ read junk
+ fi
+
+ while true; do
+ cat <<EOH
+
+
+ Pick the item that best describes your location:
+
+ 1) Africa
+ 2) North, South, Central America (includes Greenland)
+ 3) Atlantic Ocean islands
+ 4) Asia and the Middle East
+ 5) Australia
+ 6) Europe
+ 7) Indian Ocean islands
+ 8) Pacific islands (includes Hawaii)
+
+ 98) Select CMOS time status (UTC or local)
+ 99) Exit this menu
+
+EOH
+ ask 'Your choice?' 99
+ case $ans in
+ 1) select Africa;;
+ 2) select America;;
+ 3) select Atlantic;;
+ 4) select Asia;;
+ 5) select Australia;;
+ 6) select Europe;;
+ 7) select Indian;;
+ 8) select Pacific;;
+ 9) select Etc;;
+ 10) select SystemV;;
+ 98) setadjkerntz;;
+ 99) return 0;;
+ esac
+ done
+}
+
+cat <<EOH
+Welcome to `sysctl -n kern.ostype` `sysctl -n kern.osrelease`!
+
+This program will help you select a default timezone for your users and
+for system processes.
+
+EOH
+echo -n 'Press return to continue ==>'
+read return
+
+mainmenu
+exit 0
+#
+# Copyright (c) 1994 Garrett A. Wollman. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED 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 OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
diff --git a/usr.sbin/update/Makefile b/usr.sbin/update/Makefile
new file mode 100644
index 0000000..ea20d05
--- /dev/null
+++ b/usr.sbin/update/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= update
+MAN8= update.0
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/update/update.8 b/usr.sbin/update/update.8
new file mode 100644
index 0000000..78665fa
--- /dev/null
+++ b/usr.sbin/update/update.8
@@ -0,0 +1,74 @@
+.\" 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.
+.\"
+.\" @(#)update.8 8.3 (Berkeley) 4/19/94
+.\"
+.Dd April 19, 1994
+.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
+occurring 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 0000000..ae83ad1
--- /dev/null
+++ b/usr.sbin/update/update.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 1987, 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) 1987, 1990, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)update.c 8.1 (Berkeley) 6/6/93";
+#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/vidcontrol/Makefile b/usr.sbin/vidcontrol/Makefile
new file mode 100644
index 0000000..11636b9
--- /dev/null
+++ b/usr.sbin/vidcontrol/Makefile
@@ -0,0 +1,4 @@
+PROG= vidcontrol
+SRCS= vidcontrol.c decode.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/vidcontrol/decode.c b/usr.sbin/vidcontrol/decode.c
new file mode 100644
index 0000000..88861db
--- /dev/null
+++ b/usr.sbin/vidcontrol/decode.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 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.
+ *
+ * $Id: decode.c,v 1.1 1994/05/20 12:20:37 sos Exp $
+ */
+
+#include <stdio.h>
+
+int decode(FILE *fd, char *buffer)
+{
+ int n, pos = 0;
+ char *p;
+ char temp[128];
+
+#define DEC(c) (((c) - ' ') & 0x3f)
+
+ do {
+ if (!fgets(temp, sizeof(temp), fd))
+ return(0);
+ } while (strncmp(temp, "begin ", 6));
+ sscanf(temp, "begin %o %s", &n, temp);
+ for (;;) {
+ if (!fgets(p = temp, sizeof(temp), fd))
+ return(0);
+ if ((n = DEC(*p)) <= 0)
+ break;
+ for (++p; n > 0; p += 4, n -= 3)
+ if (n >= 3) {
+ buffer[pos++] = DEC(p[0])<<2 | DEC(p[1])>>4;
+ buffer[pos++] = DEC(p[1])<<4 | DEC(p[2])>>2;
+ buffer[pos++] = DEC(p[2])<<6 | DEC(p[3]);
+ }
+ else {
+ if (n >= 1) {
+ buffer[pos++] =
+ DEC(p[0])<<2 | DEC(p[1])>>4;
+ }
+ if (n >= 2) {
+ buffer[pos++] =
+ DEC(p[1])<<4 | DEC(p[2])>>2;
+ }
+ if (n >= 3) {
+ buffer[pos++] =
+ DEC(p[2])<<6 | DEC(p[3]);
+ }
+ }
+ }
+ if (!fgets(temp, sizeof(temp), fd) || strcmp(temp, "end\n"))
+ return(0);
+ return(pos);
+}
diff --git a/usr.sbin/vidcontrol/path.h b/usr.sbin/vidcontrol/path.h
new file mode 100644
index 0000000..709acbc
--- /dev/null
+++ b/usr.sbin/vidcontrol/path.h
@@ -0,0 +1,4 @@
+#define KEYMAP_PATH "/usr/share/syscons/keymaps/"
+#define FONT_PATH "/usr/share/syscons/fonts/"
+#define SCRNMAP_PATH "/usr/share/syscons/scrnmaps/"
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1
new file mode 100644
index 0000000..f3ac429
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.1
@@ -0,0 +1,118 @@
+.\"
+.\" vidcontrol - a utility for manipulating the syscons video driver
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" @(#)vidcontrol.1
+.\"
+.TH vidcontrol 1 "May 22, 1994" "" "FreeBSD"
+
+.SH NAME
+vidcontrol - a utility for manipulating the syscons video driver.
+.SH SYNOPSIS
+.na
+.B vidcontrol
+.RB [options]
+.SH DESCRIPTION
+The
+.B vidcontrol
+command is used to set various options for the syscons video driver,
+such as video mode, colors, cursor, scrnmaps, font,
+screensaver type and timeout.
+
+A new video mode is selected by specifying its name as an argument to
+.B vidcontrol
+eg. "
+.B vidcontrol 80x25
+".
+
+The modes currently supported: 80x25 and 80x50 text.
+
+The colors used when displaying text can be changed by specifying the
+foreground color (eg. "
+.B vidcontrol white
+"), or both a foreground & background
+color (eg. "
+.B vidcontrol yellow blue
+").
+
+To see the supported colors on a given platform use "
+.B vidcontrol show
+".
+
+.SH OPTIONS
+.TP
+The following command line options are supported.
+.TP
+.BI "\-r\ " foreground\ background
+Change reverse mode colors to
+.B foreground
+and
+.B background
+.
+.TP
+.BI "\-b\ " color
+Set border color to
+.B color
+(only supported on VGA hardware):
+.TP
+.BI "\-c\ " start.end
+Change the cursor apperance. The cursor is changed to a shape that starts
+on scanline
+.B start
+and ends on scanline
+.B end
+.
+.TP
+.BI "\-d\ "
+Print out current screen output map.
+.TP
+.BI "\-l\ " scrmap
+Install screen output map file from
+.I scrmap
+.TP
+.BI "\-L\ "
+Install default screen output map.
+.TP
+.BI "\-f\ " size\ file
+Load font
+.I file
+for
+.I size
+(currently, only 8x8, 8x14 or 8x16).
+The fontfile can be either uuencoded or in raw binary format.
+.TP
+.BI "\-t\ " N|off
+Sets the screensaver timeout to
+.I N
+seconds, or turns it
+.I off
+.TP
+.BI "\-s\ " NAME|help
+Sets the screensaver appearance to
+.I NAME .
+Use \-s help to print a list of the available screen savers.
+.TP
+.BI "\-x\ "
+Use hexadecimal digits for output.
+.PP
+.SH FILES
+/usr/share/syscons/fonts
+/usr/share/syscons/scrnmaps
+.SH BUGS
+Report when found.
+.SH "SEE ALSO"
+.BR kbdcontrol(1) ,
+.BR keyboard (4) ,
+.BR screen (4) ,
+.BR /sys/i386/conf/GENERICAH
+.SH AUTHORS
+Søren Schmidt (sos@login.dkuug.dk)
+
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
new file mode 100644
index 0000000..6aece12
--- /dev/null
+++ b/usr.sbin/vidcontrol/vidcontrol.c
@@ -0,0 +1,481 @@
+/*-
+ * Copyright (c) 1994 Søren Schmidt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce 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 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.
+ *
+ * $Id: vidcontrol.c,v 1.2 1994/09/15 07:28:06 sos Exp $
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <machine/console.h>
+#include <sys/errno.h>
+#include "path.h"
+
+
+char legal_colors[16][16] = {
+ "black", "blue", "green", "cyan",
+ "red", "magenta", "brown", "white",
+ "grey", "lightblue", "lightgreen", "lightcyan",
+ "lightred", "lightmagenta", "yellow", "lightwhite"
+ };
+int hex = 0;
+int number, verbose = 0;
+char letter;
+struct vid_info info;
+
+
+char *
+nextarg(int ac, char **av, int *indp, int oc)
+{
+ if (*indp < ac)
+ return(av[(*indp)++]);
+ fprintf(stderr, "%s: option requires two arguments -- %c\n", av[0], oc);
+ usage();
+ exit(1);
+ return("");
+}
+
+
+char *
+mkfullname(const char *s1, const char *s2, const char *s3)
+{
+static char *buf = NULL;
+static int bufl = 0;
+int f;
+
+
+ f = strlen(s1) + strlen(s2) + strlen(s3) + 1;
+ if (f > bufl)
+ if (buf)
+ buf = (char *)realloc(buf, f);
+ else
+ buf = (char *)malloc(f);
+ if (!buf) {
+ bufl = 0;
+ return(NULL);
+ }
+
+ bufl = f;
+ strcpy(buf, s1);
+ strcat(buf, s2);
+ strcat(buf, s3);
+ return(buf);
+}
+
+
+void
+load_scrnmap(char *filename)
+{
+ FILE *fd;
+ int i, size;
+ char *name;
+ scrmap_t scrnmap;
+ char *prefix[] = {"", "", SCRNMAP_PATH, SCRNMAP_PATH, NULL};
+ char *postfix[] = {"", ".scm", "", ".scm"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("screenmap file not found");
+ return;
+ }
+ size = sizeof(scrnmap);
+ if (decode(fd, &scrnmap) != size) {
+ rewind(fd);
+ if (fread(&scrnmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad scrnmap file\n");
+ close(fd);
+ return;
+ }
+ }
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load screenmap");
+ close(fd);
+}
+
+
+void
+load_default_scrnmap()
+{
+ int i;
+ scrmap_t scrnmap;
+
+ for (i=0; i<256; i++)
+ *((char*)&scrnmap + i) = i;
+ if (ioctl(0, PIO_SCRNMAP, &scrnmap) < 0)
+ perror("can't load default screenmap");
+}
+
+
+void
+print_scrnmap()
+{
+ unsigned char map[256];
+ int i;
+
+ if (ioctl(0, GIO_SCRNMAP, &map) < 0) {
+ perror("getting scrnmap");
+ return;
+ }
+ for (i=0; i<sizeof(map); i++) {
+ if (i > 0 && i % 16 == 0)
+ fprintf(stdout, "\n");
+ if (hex)
+ fprintf(stdout, " %02x", map[i]);
+ else
+ fprintf(stdout, " %03d", map[i]);
+ }
+ fprintf(stdout, "\n");
+
+}
+
+
+void
+load_font(char *type, char *filename)
+{
+ FILE *fd;
+ int i, io, size;
+ char *name, *fontmap;
+ char *prefix[] = {"", "", FONT_PATH, FONT_PATH, NULL};
+ char *postfix[] = {"", ".fnt", "", ".fnt"};
+
+ for (i=0; prefix[i]; i++) {
+ name = mkfullname(prefix[i], filename, postfix[i]);
+ if (fd = fopen(name, "r"))
+ break;
+ }
+ if (fd == NULL) {
+ perror("font file not found");
+ return;
+ }
+ if (!strcmp(type, "8x8")) {
+ size = 8*256;
+ io = PIO_FONT8x8;
+ }
+ else if (!strcmp(type, "8x14")) {
+ size = 14*256;
+ io = PIO_FONT8x14;
+ }
+ else if (!strcmp(type, "8x16")) {
+ size = 16*256;
+ io = PIO_FONT8x16;
+ }
+ else {
+ perror("bad font size specification");
+ close(fd);
+ return;
+ }
+ fontmap = (char*) malloc(size);
+ if (decode(fd, fontmap) != size) {
+ rewind(fd);
+ if (fread(fontmap, 1, size, fd) != size) {
+ fprintf(stderr, "bad font file\n");
+ close(fd);
+ free(fontmap);
+ return;
+ }
+ }
+ if (ioctl(0, io, fontmap) < 0)
+ perror("can't load font");
+ close(fd);
+ free(fontmap);
+}
+
+
+void
+set_screensaver_timeout(char *arg)
+{
+ int nsec;
+
+ if (!strcmp(arg, "off"))
+ nsec = 0;
+ else {
+ nsec = atoi(arg);
+ if ((*arg == '\0') || (nsec < 1)) {
+ fprintf(stderr, "argument must be a positive number\n");
+ return;
+ }
+ }
+ if (ioctl(0, CONS_BLANKTIME, &nsec) == -1)
+ perror("setting screensaver period");
+}
+
+
+void
+set_screensaver_type(char *type)
+{
+ ssaver_t saver;
+ int i, e;
+
+ if (!strcmp(type, "help")) {
+ i = 0;
+ printf("available screen saver types:\n");
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0)
+ printf("\t%s\n", saver.name);
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ } else {
+ i = 0;
+ do {
+ saver.num = i;
+ e = ioctl(0, CONS_GSAVER, &saver);
+ i ++;
+ if (e == 0 && !strcmp(type, saver.name)) {
+ if (ioctl(0, CONS_SSAVER, &saver) == -1)
+ perror("setting screensaver type");
+ return;
+ }
+ } while (e == 0);
+ if (e == -1 && errno != EIO)
+ perror("getting screensaver info");
+ else
+ fprintf(stderr, "%s: No such screensaver\n", type);
+ }
+}
+
+void
+set_cursor_values(char *size)
+{
+ int start, end;
+ int n;
+ char *v1;
+
+ start = strtol(size, &v1, 0);
+ if ((start < 0) || (*v1 != '.'))
+ goto badopt;
+ size = ++v1;
+ end = strtol(size, &v1, 0);
+ if ((end < 0) || (*size == '\0') || (*v1 != '\0')) {
+badopt:
+ fprintf(stderr,
+ "argument to -c must be start.end\n");
+ return;
+ }
+ if (verbose)
+ fprintf(stderr, "setting cursor to %d.%d\n", start, end);
+ fprintf(stdout, "[=%d;%dC", start, end);
+}
+
+
+int
+video_mode(int argc, char **argv, int *index)
+{
+ int mode;
+
+ if (*index < argc) {
+ if (!strcmp(argv[*index], "VGA_40x25"))
+ mode = SW_VGA_C40x25;
+ else if (!strcmp(argv[*index], "VGA_80x25"))
+ mode = SW_VGA_C80x25;
+ else if (!strcmp(argv[*index], "VGA_80x50"))
+ mode = SW_VGA_C80x50;
+ else if (!strcmp(argv[*index], "VGA_320x200"))
+ mode = SW_VGA_CG320;
+ else if (!strcmp(argv[*index], "EGA_80x25"))
+ mode = SW_ENH_C80x25;
+ else if (!strcmp(argv[*index], "EGA_80x43"))
+ mode = SW_ENH_C80x43;
+ else
+ return;
+ if (ioctl(0, mode, NULL) < 0)
+ perror("Cannot set videomode");
+ (*index)++;
+ }
+ return;
+}
+
+
+int
+get_color_number(char *color)
+{
+ int i;
+
+ for (i=0; i<16; i++)
+ if (!strcmp(color, legal_colors[i]))
+ return i;
+ return -1;
+}
+
+
+int
+set_normal_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if (*index < argc && (color = get_color_number(argv[*index])) != -1) {
+ (*index)++;
+ fprintf(stderr, "[=%dF", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dG", color);
+ }
+ }
+}
+
+
+set_reverse_colors(int argc, char **argv, int *index)
+{
+ int color;
+
+ if ((color = get_color_number(argv[*(index)-1])) != -1) {
+ fprintf(stderr, "[=%dH", color);
+ if (*index < argc
+ && (color = get_color_number(argv[*index])) != -1
+ && color < 8) {
+ (*index)++;
+ fprintf(stderr, "[=%dI", color);
+ }
+ }
+}
+
+
+set_border_color(char *arg)
+{
+ int color;
+
+ if ((color = get_color_number(arg)) != -1) {
+ fprintf(stderr, "[=%dA", color);
+ }
+ else
+ usage();
+}
+
+
+test_frame()
+{
+ int i;
+
+ fprintf(stdout, "[=0G\n\n");
+ for (i=0; i<8; i++) {
+ fprintf(stdout, "[=15F[=0G %2d [=%dF%-16s"
+ "[=15F[=0G %2d [=%dF%-16s "
+ "[=15F %2d [=%dGBACKGROUND[=0G\n",
+ i, i, legal_colors[i], i+8, i+8,
+ legal_colors[i+8], i, i);
+ }
+ fprintf(stdout, "[=%dF[=%dG[=%dH[=%dI\n",
+ info.mv_norm.fore, info.mv_norm.back,
+ info.mv_rev.fore, info.mv_rev.back);
+}
+
+
+usage()
+{
+ fprintf(stderr,
+"Usage: vidcontrol mode (available modes: VGA_40x25, VGA_80x25,\n"
+" VGA_80x50, VGA_320x200,\n"
+" EGA_80x25, EGA_80x43)\n"
+" show (show available colors)\n"
+" fgcol bgcol (set fore- & background colors)\n"
+" -r fgcol bgcol (set reverse fore- & background colors)\n"
+" -b color (set border color)\n"
+" -c n.m (set cursor start line n & end line m)\n"
+" -d (dump screenmap to stdout)\n"
+" -l filename (load srceenmap file filename)\n"
+" -L (load default screenmap)\n"
+" -f DxL filename (load font, D dots wide & L lines high)\n"
+" -s saver | help (set screensaver type or help for a list)\n"
+" -t N (set screensaver timeout in seconds)\n"
+" -x (use hex numbers for output)\n"
+ );
+}
+
+
+void
+main(int argc, char **argv)
+{
+ extern char *optarg;
+ extern int optind;
+ int opt;
+
+
+ info.size = sizeof(info);
+ if (ioctl(0, CONS_GETINFO, &info) < 0) {
+ perror("Must be on a vty");
+ exit(1);
+ }
+ while((opt = getopt(argc, argv, "b:c:df:l:Lr:s:t:vx")) != -1)
+ switch(opt) {
+ case 'c':
+ set_cursor_values(optarg);
+ break;
+ case 'b':
+ set_border_color(optarg);
+ break;
+ case 'd':
+ print_scrnmap();
+ break;
+ case 'f':
+ load_font(optarg,
+ nextarg(argc, argv, &optind, 'f'));
+ break;
+ case 'l':
+ load_scrnmap(optarg);
+ break;
+ case 'L':
+ load_default_scrnmap();
+ break;
+ case 'r':
+ set_reverse_colors(argc, argv, &optind);
+ break;
+ case 's':
+ set_screensaver_type(optarg);
+ break;
+ case 't':
+ set_screensaver_timeout(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'x':
+ hex = 1;
+ break;
+ default:
+ usage();
+ exit(1);
+ }
+ if (video_mode(argc, argv, &optind)) ;
+ if (set_normal_colors(argc, argv, &optind)) ;
+ if (optind < argc && !strcmp(argv[optind], "show")) {
+ test_frame();
+ optind++;
+ }
+ if ((optind != argc) || (argc == 1)) {
+ usage();
+ exit(1);
+ }
+ exit(0);
+}
+
diff --git a/usr.sbin/vipw/Makefile b/usr.sbin/vipw/Makefile
new file mode 100644
index 0000000..e1c3978
--- /dev/null
+++ b/usr.sbin/vipw/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= vipw
+SRCS= pw_util.c vipw.c
+MAN8= 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 0000000..9873f74
--- /dev/null
+++ b/usr.sbin/vipw/pw_util.c
@@ -0,0 +1,204 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
+
+/*
+ * This file is used by all the "password" programs; vipw(8), chpass(1),
+ * and passwd(1).
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "pw_util.h"
+
+extern char *tempname;
+
+void
+pw_init()
+{
+ struct rlimit rlim;
+
+ /* Unlimited resource limits. */
+ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
+ (void)setrlimit(RLIMIT_CPU, &rlim);
+ (void)setrlimit(RLIMIT_FSIZE, &rlim);
+ (void)setrlimit(RLIMIT_STACK, &rlim);
+ (void)setrlimit(RLIMIT_DATA, &rlim);
+ (void)setrlimit(RLIMIT_RSS, &rlim);
+
+ /* Don't drop core (not really necessary, but GP's). */
+ rlim.rlim_cur = rlim.rlim_max = 0;
+ (void)setrlimit(RLIMIT_CORE, &rlim);
+
+ /* Turn off signals. */
+ (void)signal(SIGALRM, SIG_IGN);
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ (void)signal(SIGTERM, SIG_IGN);
+ (void)signal(SIGTSTP, SIG_IGN);
+ (void)signal(SIGTTOU, SIG_IGN);
+
+ /* Create with exact permissions. */
+ (void)umask(0);
+}
+
+static int lockfd;
+
+int
+pw_lock()
+{
+ /*
+ * If the master password file doesn't exist, the system is hosed.
+ * Might as well try to build one. Set the close-on-exec bit so
+ * that users can't get at the encrypted passwords while editing.
+ * Open should allow flock'ing the file; see 4.4BSD. XXX
+ */
+ lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0);
+ if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1)
+ err(1, "%s", _PATH_MASTERPASSWD);
+ if (flock(lockfd, LOCK_EX|LOCK_NB))
+ errx(1, "the password db file is busy");
+ return (lockfd);
+}
+
+int
+pw_tmp()
+{
+ static char path[MAXPATHLEN] = _PATH_MASTERPASSWD;
+ int fd;
+ char *p;
+
+ if (p = strrchr(path, '/'))
+ ++p;
+ else
+ p = path;
+ strcpy(p, "pw.XXXXXX");
+ if ((fd = mkstemp(path)) == -1)
+ err(1, "%s", path);
+ tempname = path;
+ return (fd);
+}
+
+int
+pw_mkdb()
+{
+ int pstat;
+ pid_t pid;
+
+ warnx("rebuilding the database...");
+ (void)fflush(stderr);
+ if (!(pid = vfork())) {
+ execl(_PATH_PWD_MKDB, "pwd_mkdb", "-p", tempname, NULL);
+ pw_error(_PATH_PWD_MKDB, 1, 1);
+ }
+ pid = waitpid(pid, &pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ return (0);
+ warnx("done");
+ return (1);
+}
+
+void
+pw_edit(notsetuid)
+ int notsetuid;
+{
+ int pstat;
+ pid_t pid;
+ char *p, *editor;
+
+ if (!(editor = getenv("EDITOR")))
+ editor = _PATH_VI;
+ if (p = strrchr(editor, '/'))
+ ++p;
+ else
+ p = editor;
+
+ if (!(pid = vfork())) {
+ if (notsetuid) {
+ (void)setgid(getgid());
+ (void)setuid(getuid());
+ }
+ execlp(editor, p, tempname, NULL);
+ _exit(1);
+ }
+ pid = waitpid(pid, (int *)&pstat, 0);
+ if (pid == -1 || !WIFEXITED(pstat) || WEXITSTATUS(pstat) != 0)
+ pw_error(editor, 1, 1);
+}
+
+void
+pw_prompt()
+{
+ int c;
+
+ (void)printf("re-edit the password file? [y]: ");
+ (void)fflush(stdout);
+ c = getchar();
+ if (c != EOF && c != '\n')
+ while (getchar() != '\n');
+ if (c == 'n')
+ pw_error(NULL, 0, 0);
+}
+
+void
+pw_error(name, err, eval)
+ char *name;
+ int err, eval;
+{
+ if (err)
+ warn(name);
+
+ warnx("%s: unchanged", _PATH_MASTERPASSWD);
+ (void)unlink(tempname);
+ exit(eval);
+}
diff --git a/usr.sbin/vipw/pw_util.h b/usr.sbin/vipw/pw_util.h
new file mode 100644
index 0000000..9ea3672
--- /dev/null
+++ b/usr.sbin/vipw/pw_util.h
@@ -0,0 +1,42 @@
+/*-
+ * 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 0000000..18ef5ed
--- /dev/null
+++ b/usr.sbin/vipw/vipw.8
@@ -0,0 +1,93 @@
+.\" 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 0000000..c671623
--- /dev/null
+++ b/usr.sbin/vipw/vipw.c
@@ -0,0 +1,127 @@
+/*
+ * 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/xntpd/Config b/usr.sbin/xntpd/Config
new file mode 100644
index 0000000..c15ec05
--- /dev/null
+++ b/usr.sbin/xntpd/Config
@@ -0,0 +1,200 @@
+RANLIB= ranlib
+DEFS_LOCAL=-DREFCLOCK
+DEFS= -DSYS_FREEBSD -DSYS_386BSD
+AUTHDEFS= -DDES -DMD5
+CLOCKDEFS= -DLOCAL_CLOCK
+DAEMONLIBS= -lcrypt
+RESLIB=
+COPTS= -O2
+COMPILER= gcc
+LIBDEFS= -DXNTP_LITTLE_ENDIAN
+# This is the local configure file (distribution version).
+# You must modify it to fit your particular configuration
+# and name it Config.local
+# The following configuratiions can be auto-generated:
+#
+# make Config.local.green
+# make a Config.local that supports a local clock
+# (i.e. allow fallback to use of the CPU's own clock)
+# make Config.local.NO.clock
+# make a Config.local that supports no clocks
+#
+#
+# NOTE TO GREENHORNS
+#
+# For plug-'n-play and no radios or other complicated gadgetry,
+# use "make Config.local.green" as above.
+#
+# Following defines can be set in the DEFS_OPT= define:
+#
+# The flag -DDEBUG includes some debugging code. To use this, include
+# the define and start the daemon with one or more -d flags, depending
+# on your calibration of pearannoya. The daemon will not detach your
+# terminal in this case. Judicious use of grep will reduce the speaker
+# volume to bearable levels.
+#
+# To change the location of the configuration file, use a
+# -DCONFIG_FILE=\\"/local/etc/ntp.conf\\" or something similar.
+#
+# The -DSYSLOG_FILE defines allows logging messages that are normally
+# reported via syslof() in a file. The file name can be configured using
+# the configuration line "logfile <filename>" in CONFIG_FILE.
+#
+# There are three serial port system software interfaces, each of
+# which is peculiar to one or more Unix versions. Define
+# -DHAVE_SYSV_TTYS for basic System V compatibility; define -DSTREAM
+# for POSIX compatibility including System V Streams, and
+# HAVE_BSD_TTYS for 4.3bsd compatibility. Only one of these three
+# should be defined. If none are defined, HAVE_BSD_TTYS is assumed.
+# Usually these defines are already set correctly.
+#
+DEFS_OPT=-DDEBUG
+
+#
+# The DEFS_LOCAL define picks up all flags from DEFS_OPT (do not delete that)
+# and one of the following:
+#
+# The flag -DREFCLOCK causes the basic reference clock support to be
+# compiled into the daemon. If you set this you may also want to
+# configure the particular clock drivers you want in the CLOCKDEFS= line
+# below. This flag affects xntpd only. This define is included by
+# default when using the "make makeconfig" script.
+#
+# The next two sets of defines are meaningful only when radio clock
+# drivers or special 1-pps signals are to be used. For systems without
+# these features, these delicious complexities can be avoided. Ordinarily,
+# the "make makeconfig" script figures out which ones to use, but your
+# mileage may vary.
+#
+# There are three ways to utilize external 1-pps signals. Define
+# -DPPS to include just the pps routine, such as used by the DCF77(PARSE)
+# clock driver. Define -DPPSCLK to include a serial device driver
+# which avoids much of the jitter due to upper level port
+# processing. This requires a dedicated serial port and either the
+# tty_clock line discipline or tty_clk_streams module, both of
+# which are in the ./kernel directory. Define -DPPSCD to include a
+# special driver which intercepts carrier-detect transitions
+# generated by the pps signal. This requires a nondedicated serial
+# port and the ppsclock streams module in the ./kernel directory.
+# Only one of these three flags should be defined.
+#
+# The flag KERNEL_PLL causes code to be compiled for a special feature of
+# the kernel that (a) implements the phase-lock loop and (b) provides
+# a user interface to learn time, maximum error and estimated error.
+# See the file README.kern in the doc directory for further info.
+# This code is activated only if the relevant kernel features have
+# been configured; it does not affect operation of unmodified kernels.
+# To compile it, however, requires a few header files from the
+# special distribution.
+#
+# Note: following line must always start with DEFS_LOCAL= $(DEFS_OPT)
+DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL
+
+#
+# Radio clock support definitions (these only make sense if -DREFCLOCK
+# used), which is normally the case. Note that a configuration can include
+# no clocks, more than one type of clock and even multiple clocks of the
+# same type.
+#
+# For most radio clocks operating with serial ports, accuracy can
+# be considerably improved through use of the tty_clk line
+# discipline or tty_clk_STREAMS streams module found in the
+# ./kernel directory. These gizmos capture a timestamp upon
+# occurrence of an intercept character and stuff it in the data
+# stream for the clock driver to munch. To select this mode,
+# postfix the driver name with the string CLK; that is, WWVB
+# becomes WWVBCLK. If more than one clock is in use, the CLK
+# postfix can be used with any or all of them.
+#
+# Alternatively, for the best accuracy, use the ppsclock streams
+# module in the ./ppsclock directory to steal the carrier-detect
+# transition and capture a precision timestamp. At present this
+# works only with SunOS 4.1.1 or later. To select this mode,
+# postfix the driver name with the string PPS; that is, AS2201
+# becomes AS2201PPS. If more than one clock is in use, the PPS
+# postfix should be used with only one of them. If any PPS
+# postfix is defined, the -DPPSPPS define should be used on the
+# DEFS above.
+#
+# Define -DLOCAL_CLOCK for a local pseudo-clock to masquerade as a
+# reference clock for those subnets without access to the real thing.
+# Works in all systems and requires no hardware support. This is defined
+# by default when using the "make makeconfig" script and greenhorn
+# configuraiton.
+#
+# Define -DPST for a PST/Traconex 1020 WWV/H receiver. The driver
+# supports both the CLK and PPS modes. It should work in all systems
+# with a serial port.
+#
+# Define -DWWVB for a Spectracom 8170 or Netclock/2 WWVB receiver. It
+# should work in all systems with a serial port. The driver supports
+# both the CLK and PPS modes if the requisite kernel support is installed.
+#
+# Define -DCHU for a special CHU receiver using an ordinary shortwave
+# radio. This requires the chu_clk line discipline or chu_clk_STREAMS
+# module in the ./kernel directory. At present, this driver works only
+# on SunOS4.1.x; operation in other systems has not been confirmed.
+# Construction details for a suitable modem can be found in the ./gadget
+# directory. The driver supports # neither the CLK nor PPS modes.
+#
+# Define -DPARSE for a DCF77/GPS(GENERIC) receiver. For best performance
+# this requires a special parsestreams STREAMS (SunOS 4.x) module in the
+# ./parse directory. Define -DPARSEPPS for PPS support via the
+# DCF77/GPS (GENERIC) receiver; also, define -DPPS in the DEFS above.
+# Define: -DCLOCK_MEINBERG for Meinberg clocks
+# -DCLOCK_SCHMID for Schmid receivers
+# -DCLOCK_DCF7000 for ELV DCF7000
+# -DCLOCK_RAWDCF for simple receivers (100/200ms pulses on Rx)
+# -DCLOCK_TRIMSV6 for Trimble SV6 GPS receiver
+#
+# Define -DMX4200PPS for a Magnavox 4200 GPS receiver. At present, this
+# driver works only on SunOS4.1.x with CPU serial ports only. The PPS
+# mode is required.
+#
+# Define -DAS2201 for an Austron 2200A or 2201A GPS receiver. It should
+# work in all systems with a serial port. The driver does not support the
+# CLK mode, but does support the PPS mode. If the radio is connected to
+# more than one machine, the PPS mode is required.
+#
+# Define -DGOES for a Kinemetrics/TrueTime 468-DC GOES receiver. This
+# driver is known to work with some other TrueTime products as well,
+# including the GPS-DC GPS receiver. It should work in all systems with
+# a serial port. The driver does not support the CLK mode, but does
+# support the PPS mode.
+#
+# Define -DOMEGA for a Kinemetrics/TrueTime OM-DC OMEGA receiver. It
+# should work in all systems with a serial port. The driver does not
+# support the CLK mode, but does support the PPS mode.
+#
+# Define -DTPRO for a KSI/Odetics TPRO-S IRIG-B timecode reader. This
+# requires the SunOS interface driver available from KSI. The driver
+# supports neither the CLK nor PPS modes.
+#
+# Define -DLEITCH for a Leitch CSD 5300 Master Clock System Driver for
+# the HP 5061B Cesium Clock. It should work in all systems with a serial
+# port. The driver does not support the CLK mode, but does support the
+# PPS mode.
+#
+# Define -DMSFEESPPS for an EES M201 MSF receiver. It currently only works
+# under SunOS 4.x with the PPSCD (ppsclock) STREAMS module, but the RCS
+# files on cl.cam.ac.uk still has support for CLK and CBREAK modes.
+#
+# Define -DIRIG for a IRIG-B timecode timecode using the audio codec of
+# the Sun SPARCstations. This requires a modified BSD audio driver and
+# exclusive access to the audio port. A memo describing how it works and
+# how to install the driver is in the README.irig file in the ./doc
+# directory.
+#
+# Note: The following defines result in compilation of all the above radio
+# clocks. This works on a Sun 4.1.x system which has tty_clk, chu_clk and
+# ppsclock STREAMS modules installed. If the trailing CLK and PPS suffixes
+# are removed and the IRIG, PARSE* and CLOCK* deleted, all of the rest compile
+# under Ultrix 4.2a/3. If the MX4200 is removed, all the rest compile on a DEC
+# OSF/1 Alpha.
+#
+CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH
+
+#
+# Directory into which binaries should be installed (default /usr/local)
+#
+BINDIR= /usr/local/bin
diff --git a/usr.sbin/xntpd/Config.sed b/usr.sbin/xntpd/Config.sed
new file mode 100644
index 0000000..fe5a9b7
--- /dev/null
+++ b/usr.sbin/xntpd/Config.sed
@@ -0,0 +1,14 @@
+s~^RANLIB=.*~RANLIB= ranlib~
+s~^DEFS_LOCAL=.*~DEFS_LOCAL=-DREFCLOCK~
+s~^DEFS=.*~DEFS= -DSYS_FREEBSD -DSYS_386BSD~
+s~^AUTHDEFS=.*~AUTHDEFS= -DDES -DMD5~
+s~^CLOCKDEFS=.*~CLOCKDEFS= -DLOCAL_CLOCK~
+s~^DAEMONLIBS=.*~DAEMONLIBS= -lcrypt~
+s~^RESLIB=.*~RESLIB=~
+s~^COPTS=.*~COPTS= -O2~
+s~^COMPILER=.*~COMPILER= gcc~
+s~^LIBDEFS=.*~LIBDEFS= -DXNTP_LITTLE_ENDIAN~
+s~^DEFS_OPT=.*~DEFS_OPT=-DDEBUG~
+s~^DEFS_LOCAL=.*~DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL~
+s~^CLOCKDEFS=.*~CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH~
+s~^BINDIR=.*~BINDIR= /usr/local/bin~
diff --git a/usr.sbin/xntpd/Makefile b/usr.sbin/xntpd/Makefile
index b9b0e88..8d724c5 100644
--- a/usr.sbin/xntpd/Makefile
+++ b/usr.sbin/xntpd/Makefile
@@ -1,344 +1,8 @@
-# WARNING:
-# CONTENTS UNDER PRESSURE.
-# HIGHLY FLAMMABLE.
-# RISK OF SHOCK.
-# DO NOT ATTEMPT TO OPEN COVER.
-# NO USER SERVICEABLE PARTS INSIDE.
-# REFER SERVICING TO QUALIFIED PERSONNEL.
#
-# The vendor hits you...
-# You try to hit the vendor...
-# You die.
+# Makefile for xntpd.
+# $Id$
#
-# Unfortunately the above is no fun...
-#
-# During testing/porting we have found a long list
-# of "make" and "sh" and "awk" features in different implementations.
-# Some goodies (make good horror stories for your kids 8-():
-# gmake 3.62
-# non standard target construction
-#
-# pmake (e. g. NetBSD on MAC, possible other BNR2+pmake systems)
-# skips '' (empty string positional) args to sh
-# (this leads to following stupid constructions
-# sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'")
-#
-# Following Makefile construction fails for no
-# apparent reason (at least to me)
-# doit:
-# $(MAKE) MAKE=\"$(MAKE)\" all
-#
-# all:
-# @echo all done.
-#
-# for the "make MAKE=make" call not for "make" or
-# "make -e MAKE=make". Use the last form if you suffer
-# from that kind of make problems. (Easily detected
-# by failure to build with the message:
-# "don't know how to make make".
-#
-# sh (Ultrix 4.2 MIPS)
-# shell broken (reversed pipe construction "false | true"
-# returns false - major bummer)
-#
-# awk (EP/IX 2.?)
-# unable to do regexp matches
-# (aka awk '/..*/ { print; }' fails on match)
-#
-# Usually the vendor should fix these bugs in vital utilities.
-# We try to circumvent these bugs in a hopefully portable way.
-# If you can reproduce these bugs on your system please bug your
-# vendor to fix them. We are not trying anything fancy in here and
-# we are shocked that even the most common tools fail so miserably.
-# By the time you get this code the above utilities may already
-# have been fixed. Hopefully one day we do not have to cope with
-# this kind of broken utilities.
-#
-# Sorry about the situation,
-# Frank Kardel
-#
-SHELL=/bin/sh
-CONF = Config
-CONFL = $(CONF).local
-CONFLD= $(CONFL).dist
-TARGETS = xntpd/xntpd xntpdc/xntpdc ntpq/ntpq ntpdate/ntpdate \
- ntptrace/ntptrace authstuff/authspeed util/tickadj
-OPTTARG = adjtime/adjtimed util/ntptime util/precision
-REFCONF=
-COMPRESSOR=compress
-# Base distribution name (will be extended by <VERSION>.tar.<compressorsuffix>)
-DISTNAME=xntp-
-MAKE= make
-
-all: version $(TARGETS) kernel_modules
-
-$(TARGETS): VERSION $(CONF)
-
-version:
- @echo '### Building XNTP:' "`egrep '^.*=.*$$' VERSION | tr '\012' ';'`"
-
-makeconfig:
- sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'"
-
-$(CONFL).NO.clock:
- @echo '###' creating $(CONFL) for absolutely '*NO*' clocks '*AT ALL*'
- rm -f $(CONFL)-t $(CONFL)
- cat < $(CONFLD) > $(CONFL)-t && mv $(CONFL)-t $(CONFL)
-
-$(CONFL).green:
- @echo '###' creating $(CONFL) for greenhorns '(local refclock only)'
- rm -f $(CONFL)-t $(CONFL)
- sed 's/#GREEN//' < $(CONFLD) > $(CONFL)-t && mv $(CONFL)-t $(CONFL)
-
-$(CONFL):
- @echo ''
- @echo '### creating a $(CONFL) file as none existed.'
- @echo '### Use "make refconf" if you have a radio clock'
- @echo ''
- @$(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" $(CONFL).green
-
-$(CONF): $(CONFL)
- @echo
- @echo '###' creating new configuration
- @sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'"
-
-refconf: $(CONF)
- -@sh refclocks/rconfig '$(REFCONF)'
- @sh -c "./scripts/makeconfig.sh '$(OS)' '$(COMP)'"
-
-kernel_modules: kernel/Makefile
- @cd kernel && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-xntpd/xntpd: lib/libntp.a parse/libparse.a xntpd/Makefile FRC
- @echo
- @echo '###' creating NTP daemon
- @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-xntpdc/xntpdc: lib/libntp.a xntpdc/Makefile FRC
- @echo
- @echo '###' creating XNTPDC utility
- @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-ntpq/ntpq: lib/libntp.a ntpq/Makefile FRC
- @echo
- @echo '###' creating NTPQ utility
- @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-ntptrace/ntptrace: lib/libntp.a ntptrace/Makefile FRC
- @echo
- @echo '###' creating NTPTRACE utility
- @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-ntpdate/ntpdate: lib/libntp.a ntpdate/Makefile FRC
- @echo
- @echo '###' creating NTPDATE utility
- @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-authstuff/authspeed: lib/libntp.a authstuff/Makefile FRC
- @echo
- @echo '###' creating AUTH utilities
- @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-util/tickadj: util/Makefile lib/libntp.a FRC
- @echo
- @echo '###' creating TICKADJ utility
- @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-lib/libntp.a: lib/*.c lib/Makefile adjtime/Makefile
- @echo
- @echo '###' creating NTP library
- @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-parse/libparse.a: parse/*.c parse/Makefile parse/util/Makefile lib/libntp.a
- @echo
- @echo '### creating PARSE subsystem (if configured)'
- @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)"
-
-FRC:
-
-savebin:
- -@test -d bin || mkdir bin
- @echo
- @echo '### saving $(TARGETS) $(OPTTARG) in bin'
- -@for f in $(TARGETS) $(OPTTARG); \
- do test -f $$f && mv $$f bin/. && echo "### saved $$f in bin/"; \
- done; \
- true
-
-neatneat:
- @echo '###' cleaning derived config files
- -@rm -f $(CONF).sed $(CONF)
-
-neat:
- @echo '###' cleaning top level left overs
- -@rm -f eddep makedep Makefile.bak make.log make.out
-
-distclean: neatneat clean
- @echo '###' cleaning configuration dependent Makefiles
- -@find . -name Makefile -print | \
- while read X; do \
- if [ -f "$$X.tmpl" ]; then \
- rm -f "$$X"; \
- else \
- :; \
- fi \
- done
- @echo '###' cleaning old scratch files
- -@find . \( -name '*.rej' -o -name '*.orig' -o -name '*~' -o \
- -name '.version' -o -name '#*' -o -name '.#*' -o \
- -name core -o -name version.c \) -print | xargs rm -f
- @echo '###' cleaning saved binaries
- -@rm -fr bin
-
-clean: neat
- @echo '###' cleaning adjtime
- @cd adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" -f Makefile.tmpl $@
- @echo '###' cleaning authstuff
- @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning clockstuff
- @cd clockstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning lib
- @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning ntpdate
- @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning ntpq
- @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning ntptrace
- @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning util
- @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning xntpd
- @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning xntpdc
- @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
- @echo '###' cleaning parse
- @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" $@
-
-install: all
- @echo installing from xntpd
- @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from xntpdc
- @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from ntpq
- @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from ntptrace
- @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from ntpdate
- @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from util
- @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
- @echo installing from parse
- @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" install
-
-dist:
- @echo '### building distribution ...'
- @$(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" MAKE="$(MAKE)" distclean
- @DISTVERSION="`sed -e 's/^[ ]*[Vv][Ee][Rr][Ss][Ii][Oo][Nn][ ]*=\(.*\)$$/\1/' VERSION | \
- sed -e 's/[^0-9a-zA-Z\.]/_/g; s/__*/_/g; s/_*$$//'`" && \
- echo "### creating distribution file $(DISTNAME)$${DISTVERSION}.tar" && \
- rm -f $(DISTNAME)$${DISTVERSION}.tar $(DISTNAME)$${DISTVERSION}.tar.* && \
- tar cfv $(DISTNAME)$${DISTVERSION}.tar `ls | egrep -v "^$(CONFL)$$|^$(DISTNAME)$${DISTVERSION}.tar$$"` && \
- $(COMPRESSOR) -v $(DISTNAME)$${DISTVERSION}.tar
-
-$(CONF).sed: $(CONF) Makefile
- @sed -n -e 's:^\([^ ]*\)=[ ]*\(.*\):s~^\1=.*~&~:p' < $(CONF) > $@
-
-depend:
- find . -name Makefile.tmpl -print > eddep
- echo >> makedep
- sed -e 's:^\./::' -e '/^Makefile/d' \
- -e h \
- -e 's/^\(.*\)\.tmpl$$/\1: \1.tmpl $${CONF}.sed/' -e p -e g \
- -e 's/.*/ @echo/' -e p -e g \
- -e 's:^\(.*\)/Makefile\.tmpl$$: @echo '"'###'"' updating Makefile in \1:' -e p -e g \
- -e 's/.*/ @sed -f $${CONF}.sed < $$@.tmpl > $$@/' -e p -e g \
- -e 's:^\(.*\)/Makefile\.tmpl$$: @echo '"'###'"' cleaning in \1:' -e p -e g \
- -e 's:^\(.*\)/Makefile\.tmpl$$: @cd \1 \&\& $$(MAKE) $$(MFLAGS) MFLAGS="$$(MFLAGS)" -f Makefile.tmpl MAKE="$$(MAKE)" clean:p' \
- < eddep >> makedep
- echo '/^# DO NOT DELETE THIS LINE/+1,$$d' >eddep
- echo '$$r makedep' >>eddep
- echo 'w' >>eddep
- cp Makefile Makefile.bak
- /bin/ed - Makefile < eddep
- rm eddep makedep
-# DO NOT DELETE THIS LINE -- It is used by 'make depend' to update this file
+SUBDIR= lib parse xntpd xntpdc ntpq ntpdate ntptrace xntpres authstuff util
-adjtime/Makefile: adjtime/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in adjtime
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in adjtime
- @cd adjtime && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-authstuff/Makefile: authstuff/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in authstuff
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in authstuff
- @cd authstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-clockstuff/Makefile: clockstuff/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in clockstuff
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in clockstuff
- @cd clockstuff && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-kernel/Makefile: kernel/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in kernel
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in kernel
- @cd kernel && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-lib/Makefile: lib/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in lib
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in lib
- @cd lib && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-ntpdate/Makefile: ntpdate/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in ntpdate
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in ntpdate
- @cd ntpdate && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-ntpq/Makefile: ntpq/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in ntpq
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in ntpq
- @cd ntpq && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-ntptrace/Makefile: ntptrace/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in ntptrace
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in ntptrace
- @cd ntptrace && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-util/Makefile: util/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in util
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in util
- @cd util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-xntpd/Makefile: xntpd/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in xntpd
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in xntpd
- @cd xntpd && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-xntpdc/Makefile: xntpdc/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in xntpdc
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in xntpdc
- @cd xntpdc && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-parse/util/Makefile: parse/util/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in parse/util
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in parse/util
- @cd parse/util && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
-parse/Makefile: parse/Makefile.tmpl ${CONF}.sed
- @echo
- @echo '###' updating Makefile in parse
- @sed -f ${CONF}.sed < $@.tmpl > $@
- @echo '###' cleaning in parse
- @cd parse && $(MAKE) $(MFLAGS) MFLAGS="$(MFLAGS)" -f Makefile.tmpl MAKE="$(MAKE)" clean
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/xntpd/Makefile.inc b/usr.sbin/xntpd/Makefile.inc
new file mode 100644
index 0000000..28ff220
--- /dev/null
+++ b/usr.sbin/xntpd/Makefile.inc
@@ -0,0 +1,7 @@
+DEFS_LOCAL=-DREFCLOCK -DPARSE
+NTPDEFS= -DSYS_FREEBSD -DSYS_386BSD -DHAVE_GETBOOTFILE
+AUTHDEFS= -DMD5
+CLOCKDEFS= -DLOCAL_CLOCK -DPST -DWWVB -DAS2201 -DGOES -DGPSTM -DOMEGA \
+ -DLEITCH -DTRAK
+CFLAGS+= ${NTPDEFS} ${DEFS_LOCAL} ${AUTHDEFS} ${CLOCKDEFS} ${COPTS}
+BINDIR?= /usr/sbin
diff --git a/usr.sbin/xntpd/README.FreeBSD b/usr.sbin/xntpd/README.FreeBSD
new file mode 100644
index 0000000..4dffdc8
--- /dev/null
+++ b/usr.sbin/xntpd/README.FreeBSD
@@ -0,0 +1,84 @@
+ $Id$
+
+This version of NTP was converted to the BSD-style Makefile system by
+Garrett Wollman (wollman@freefall.cdrom.com); it is based on version
+3.3s (late beta) from the University of Delaware.
+
+Besides the Makefile changes, the DES code has been completely removed
+in order to make this code exportable. If you have a legal copy of
+`authdes.c', you can just add it to the lib/ directory and add `-DDES'
+to the AUTHDEFS in Makefile.inc.
+
+You can change CLOCKDEFS in the same file to add other reference clocks.
+
+This version of xntpd knows how to talk to the kernelized NTP PLL which is
+present in versions of FreeBSD-current after 21 April 1994. When this code
+is more widely released, I'll provide the patches to Mills.
+
+----------------------------------------------------
+Support for Conrad electronic's "DCF-77 Uhr, Mobil".
+----------------------------------------------------
+Conrad electronic in Germany,, Phone (+49) 962230111 (?), sells a gadget
+called "DCF77 Uhr, mobil", which is a DCF77 timecode receiver with a
+rs-232 interface. The price is around DM130.
+ 9-pin interface is Order# 97 94 57 66
+ 25-pin interface is Order# 97 94 81 66
+
+You must define
+ -DDCF77 -DPPS -DFREEBSD_CONRAD -DDEBUG
+when you compile xntpd. You can later remove -DDEBUG, if you feel like it.
+
+You must also have
+ options COM_BIDIR
+defined in your kernel, and finally the ttyport you intend to use must
+have special interrupt vector:
+ device sio1 at isa? port "IO_COM2" tty irq 3 vector siointrts
+ ^^^^^^^^^^^^
+connect the radio-clock to the tty port and link it to /dev/refclock-0:
+
+ cd /dev
+ sh MAKEDEV cua1
+ ln -s /dev/cua01 /dev/refclock-0
+
+make a directory to gather statistics in:
+ mkdir /var/tmp/ntp
+
+Create a /etc/ntp.conf along these lines:
+
+ # DCF77 without PPS
+ server 127.127.8.20
+ # DCF77 with PPS
+ #server 127.127.8.148 prefer
+
+ driftfile /var/tmp/ntp/ntp.drift
+ statsdir /var/tmp/ntp
+ statistics loopstats
+ statistics peerstats
+ statistics clockstats
+ filegen peerstats file peerstats type day enable
+ filegen loopstats file loopstats type day enable
+ filegen clockstats file clockstats type day enable
+
+Try to start it:
+ comcontrol ttyd1 bidir
+ tickadj -A
+ xntpd -d -d -d
+
+You should see the red LED flash on the receiver every second now. You
+may have to experiment a bit with the location, and possibly adjust the
+minute variable resistor inside to get a good signal. Be aware, that just
+because you see the light flash, is not the same as the signal being
+received by the computer. The chip doing the work in the reciver uses
+less than 1 micro-ampere, so even if RTS isn't pulled low, it will happily
+receive, but be unable to buffer the signal to the rs-232 levels needed.
+
+You can see what's going on in /var/log/messages, and query the
+daemon using xntpdc and ntpq, in particular the "clockvar" command
+of ntpq will tell about the clocks healt.
+
+I live in Slagelse, Denmark, which is ~1000 Km from Mainflingen, yet
+I have +/- 2 ms precision from this cheap gadget. If you have a very
+stable signal, you can use the 'pps' address instead to improve your
+timing.
+
+Have fun... Poul-Henning Kamp <phk@login.dkuug.dk>
diff --git a/usr.sbin/xntpd/authstuff/Makefile b/usr.sbin/xntpd/authstuff/Makefile
new file mode 100644
index 0000000..79b2d9d
--- /dev/null
+++ b/usr.sbin/xntpd/authstuff/Makefile
@@ -0,0 +1,27 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 21:06:20 wollman Exp $
+#
+# Most of the programs in this directory are completely useless for the
+# NTP configuration that we provide by default.
+# We provide the `md5' program as a public service.
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= md5
+
+SRCS= md5driver.c
+NOMAN=
+
+install:
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/authstuff/md5driver.c b/usr.sbin/xntpd/authstuff/md5driver.c
index 0d7e132..a608add 100644
--- a/usr.sbin/xntpd/authstuff/md5driver.c
+++ b/usr.sbin/xntpd/authstuff/md5driver.c
@@ -1,4 +1,4 @@
-/*
+/* md5driver.c,v 3.1 1993/07/06 01:05:07 jbj Exp
***********************************************************************
** md5driver.c -- sample test routines **
** RSA Data Security, Inc. MD5 Message-Digest Algorithm **
@@ -25,7 +25,7 @@
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
-#if defined(SYS_BSDI) || defined(SYS_44BSD)
+#ifdef SYS_BSDI
#include <sys/time.h>
#endif /* SYS_BSDI */
#include "md5.h"
@@ -57,7 +57,7 @@ MD5_CTX *mdContext;
#define TEST_BLOCKS 10000
/* number of test bytes = TEST_BLOCK_SIZE * TEST_BLOCKS */
-static long TEST_BYTES = (long)TEST_BLOCK_SIZE * (long)TEST_BLOCKS;
+static LONG TEST_BYTES = (LONG)TEST_BLOCK_SIZE * (LONG)TEST_BLOCKS;
/* A time trial routine, to measure the speed of MD5.
Measures wall time required to digest TEST_BLOCKS * TEST_BLOCK_SIZE
@@ -76,7 +76,7 @@ MDTimeTrial ()
data[i] = (unsigned char)(i & 0xFF);
/* start timer */
- printf ("MD5 time trial. Processing %ld characters...\n", (long)TEST_BYTES);
+ printf ("MD5 time trial. Processing %ld characters...\n", TEST_BYTES);
time (&startTime);
/* digest data in TEST_BLOCK_SIZE byte blocks */
@@ -90,10 +90,10 @@ MDTimeTrial ()
MDPrint (&mdContext);
printf (" is digest of test input.\n");
printf
- ("Seconds to process test input: %ld\n", (long)endTime-startTime);
+ ("Seconds to process test input: %ld\n", (LONG)(endTime-startTime));
printf
("Characters processed per second: %ld\n",
- (long)(TEST_BYTES/(endTime-startTime)));
+ TEST_BYTES/(endTime-startTime));
}
/* Computes the message digest for string inString.
diff --git a/usr.sbin/xntpd/clockstuff/Makefile b/usr.sbin/xntpd/clockstuff/Makefile
new file mode 100644
index 0000000..425d79d
--- /dev/null
+++ b/usr.sbin/xntpd/clockstuff/Makefile
@@ -0,0 +1,16 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 21:06:24 wollman Exp $
+#
+
+PROG= propdelay
+LDADD+= -L${.CURDIR}/../lib -lntp -lm
+DPADD+= ${.CURDIR}/../lib/libntp.a ${LIBM}
+
+SRCS= propdelay.c
+NOMAN=
+
+install:
+
+CLEANFILES+= chutest clktest chutest.o clktest.o
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/compilers/hpux10+.cc b/usr.sbin/xntpd/compilers/hpux10+.cc
new file mode 100644
index 0000000..cf058ef
--- /dev/null
+++ b/usr.sbin/xntpd/compilers/hpux10+.cc
@@ -0,0 +1 @@
+COMPILER=cc +O1
diff --git a/usr.sbin/xntpd/doc/ntpq.8 b/usr.sbin/xntpd/doc/ntpq.8
index b323c73..ad37476 100644
--- a/usr.sbin/xntpd/doc/ntpq.8
+++ b/usr.sbin/xntpd/doc/ntpq.8
@@ -1,5 +1,5 @@
''' $Header
-'''
+'''
.de Sh
.br
.ne 5
@@ -48,7 +48,7 @@ ntpq - standard Network Time Protocol query program
[
.B -inp
] [
-.B -c
+.B -c
.I command
] [
.I host
@@ -57,26 +57,26 @@ ntpq - standard Network Time Protocol query program
]
.SH DESCRIPTION
.I Ntpq
-is used to query NTP servers which implement the recommended NTP mode 6
-control message format about current state and to request changes in
-that state. The program may be run either in interactive mode or
-controlled using command line arguments. Requests to read and write
-arbitrary variables can be assembled, with raw and pretty\-printed
-output options being available.
+is used to query NTP servers which implement the recommended NTP
+mode 6 control message format about current state and to request
+changes in that state. The
+program may be run either in interactive mode or controlled using
+command line arguments. Requests to read and write arbitrary
+variables can be assembled, with raw and pretty\-printed output
+options being available.
.I Ntpq
-can also obtain and print a list of peers in a common format by sending
-multiple queries to the server.
+can also obtain and print a list of peers in a common format
+by sending multiple queries to the server.
.PP
If one or more request options is included on the command line when
.I ntpq
-is executed, each of the requests will be sent to the NTP servers
-running on each of the hosts given as command line arguments, or on
+is executed, each of the requests will be sent to the NTP servers running
+on each of the hosts given as command line arguments, or on
.I localhost
-by default. If no request options are given,
+by default. If no request options are given,
.I ntpq
will attempt to read commands from the standard input and execute these
-on the NTP server running on the first host given on the command line,
-again
+on the NTP server running on the first host given on the command line, again
defaulting to
.I localhost
when no other host is specified.
@@ -86,54 +86,53 @@ will prompt for commands if the standard input is a terminal device.
.I Ntpq
uses NTP mode 6 packets to communicate with the NTP server, and hence
can be used to query any compatable server on the network which permits
-it. Note that since NTP is a UDP protocol this communication will be
+it. Note that since NTP is a UDP protocol this communication will be
somewhat unreliable, especially over large distances in terms of network
topology.
.I Ntpq
makes one attempt to retransmit requests, and will time requests out if
the remote host is not heard from within a suitable time out time.
.PP
-Command line options are described following. Specifying a command line
-option other than
+Command line options are described following. Specifying a command
+line option other than
.B -i
or
.B -n
will cause the specified query (queries) to be sent to the indicated
-host(s) immediately. Otherwise,
+host(s) immediately. Otherwise,
.I ntpq
-will attempt to read interactive format commands from the standard
-input.
+will attempt to read interactive format commands from the standard input.
.Ip -c 8
The following argument is interpreted as an interactive format command
and is added to the list of commands to be executed on the specified
-host(s). Multiple
+host(s). Multiple
.B -c
options may be given.
.Ip -i 8
Force
.I ntpq
-to operate in interactive mode. Prompts will be written to the standard
-output and commands read from the standard input.
+to operate in interactive mode. Prompts will be written to the
+standard output and commands read from the standard input.
.Ip -n 8
Output all host addresses in dotted\-quad numeric format rather than
converting to the canonical host names.
.Ip -p 8
-Print a list of the peers known to the server as well as a summary of
-their state. This is equivalent to the \*(L"peers\*(R" interactive
+Print a list of the peers known to the server as well as a summary
+of their state. This is equivalent to the \*(L"peers\*(R" interactive
command.
.SH INTERNAL COMMANDS
.PP
-Interactive format commands consist of a keyword followed by zero to
-four arguments. Only enough characters of the full keyword to uniquely
-identify the command need be typed. The output of a command is normally
-sent to the standard output, but optionally the output of individual
-commands may be sent to a file by appending a \*(L">\*(R", followed by a
-file name, to the command line.
+Interactive format commands consist of a keyword followed by zero
+to four arguments. Only enough characters of the full keyword to
+uniquely identify the command need be typed. The output of a command
+is normally sent to the standard output, but optionally the output of
+individual commands may be sent to a file by appending a \*(L">\*(R",
+followed by a file name, to the command line.
.PP
A number of interactive format commands are executed entirely within the
.I ntpq
-program itself and do not result in NTP mode 6 requests being sent to a
-server. These are described following.
+program itself and do not result in NTP mode 6 requests being sent
+to a server. These are described following.
.PP
.B ?
[
@@ -144,7 +143,7 @@ A \*(L"?\*(R" by itself will print a list of all the command keywords
known to this incarnation of
.IR ntpq .
A \*(L"?\*(R" followed by a command keyword will print funcation and
-usage information about the command. This command is probably a better
+usage information about the command. This command is probably a better
source of information about
.I ntpq
than this manual page.
@@ -152,8 +151,8 @@ than this manual page.
.B timeout
.I millseconds
.PP
-Specify a time out period for responses to server queries. The default
-is about 5000 milliseconds. Note that since
+Specify a time out period for responses to server queries. The default
+is about 5000 milliseconds. Note that since
.I ntpq
retries each query once after a time out the total waiting time for a
time out will be twice the time out value set.
@@ -162,10 +161,10 @@ time out will be twice the time out value set.
.I milliseconds
.PP
Specify a time interval to be added to timestamps included in requests
-which require authentication. This is used to enable (unreliable) server
+which require authentication. This is used to enable (unreliable) server
reconfiguration over long delay network paths or between machines whose
-clocks are unsynchronized. Actually the server does not now require time
-stamps in authenticated requests, so this command may be obsolete.
+clocks are unsynchronized. Actually the server does not now require
+time stamps in authenticated requests, so this command may be obsolete.
.PP
.B host
.I hostname
@@ -182,30 +181,30 @@ address.
.B verbose
]
.PP
-Poll the current server in client mode. The first argument is the number
-of times to poll (default is 1) while the second argument may be given
-to obtain a more detailed output of the results. This command is
-currently just wishful thinking.
+Poll the current server in client mode. The first argument is the
+number of times to poll (default is 1) while the second argument may
+be given to obtain a more detailed output of the results. This command
+is currently just wishful thinking.
.PP
.B keyid
.I #
.PP
This command allows the specification of a key number to be used to
-authenticate configuration requests. This must correspond to a key
-number the server has been configured to use for this purpose.
+authenticate configuration requests. This must correspond to a
+key number the server has been configured to use for this purpose.
.PP
.B passwd
.PP
This command prompts you to type in a password (which will not be
-echoed) which will be used to authenticate configuration requests. The
-password must correspond to the key configured for use by the NTP server
-for this purpose if such requests are to be successful.
+echoed) which will be used to authenticate configuration requests. The
+password must correspond to the key configured for use by the NTP
+server for this purpose if such requests are to be successful.
.PP
.B "hostnames yes|no"
.PP
If \*(L"yes\*(R" is specified, host names are printed in information
-displays. If \*(L"no\*(R" is given, numeric addresses are printed
-instead. The default is \*(L"yes\*(R" unless modified using the command
+displays. If \*(L"no\*(R" is given, numeric addresses are printed
+instead. The default is \*(L"yes\*(R" unless modified using the command
line
.B -n
switch.
@@ -213,15 +212,15 @@ switch.
.B raw
.PP
Causes all output from query commands is printed as received from the
-remote server. The only formating/intepretation done on the data is to
-transform nonascii data into a printable (but barely understandable)
+remote server. The only formating/intepretation done on the data is
+to transform nonascii data into a printable (but barely understandable)
form.
.PP
.B cooked
.PP
-Causes output from query commands to be \*(L"cooked\*(R". Variables
+Causes output from query commands to be \*(L"cooked\*(R". Variables
which are recognized by the server will have their values reformatted
-for human consumption. Variables which
+for human consumption. Variables which
.I ntpq
thinks should have a decodeable value but didn't are marked with a
trailing \*(L"?\*(R".
@@ -231,24 +230,23 @@ trailing \*(L"?\*(R".
.PP
Sets the NTP version number which
.I ntpq
-claims in packets. Defaults to 3, Note that mode 6 control messages (and
-modes, for that matter) didn't exist in NTP version 1. There appear to
-be no servers left which demand version 1.
+claims in packets. Defaults to 3, Note that mode 6 control messages (and modes,
+for that matter) didn't exist in NTP version 1. There appear to be no
+servers left which demand version 1.
.PP
.B authenticate
.B yes|no
.PP
Normally
.I ntpq
-does not authenticate requests unless they are write requests. The
-command
+does not authenticate requests unless they are write requests. The command
.B authenticate yes
causes
.I ntpq
-to send authentication with all requests it makes. Authenticated
-requests causes some servers to handle requests slightly differently,
-and can occasionally melt the CPU in fuzzballs if you turn
-authentication on before doing a peer display.
+to send authentication with all requests it makes. Authenticated requests
+causes some servers to handle requests slightly differently, and can
+occasionally melt the CPU in fuzzballs if you turn authentication on before
+doing a peer display.
.PP
.B addvars
.IR <variable_name>[=<value>] [,...]
@@ -256,24 +254,25 @@ authentication on before doing a peer display.
.IR <variable_name> [,...]
.B clearvars
.PP
-The data carried by NTP mode 6 messages consists of a list of items of
-the form
+The data carried by NTP mode 6 messages consists of a list of items
+of the form
.IP "" 8
<variable_name>=<value>
.PP
where the \*(L"=<value>\*(R" is ignored, and can be omitted, in requests
to the server to read variables.
.I Ntpq
-maintains an internal list in which data to be included in control
-messages can be assembled, and sent using the
+maintains an internal list in which data to be included in control messages
+can be assembled, and sent using
+the
.B readlist
and
.B writelist
-commands described below. The
+commands described below. The
.B addvars
command allows variables and their optional values to be added to the
-list. If more than one variable is to be added, the list should be
-comma\-separated and not contain white space. The
+list. If more than one variable is to be added, the list should be
+comma\-separated and not contain white space. The
.B rmvars
command can be used to remove individual variables from the list, while
the
@@ -294,15 +293,16 @@ Exit
Each peer known to an NTP server has a 16 bit integer
.I association
.I identifier
-assigned to it. NTP control messages which carry peer variables must
-identify the peer the values correspond to by including its association
-ID. An association ID of 0 is special, and indicates the variables are
-system variables, whose names are drawn from a separate name space.
-.PP
-Control message commands result in one or more NTP mode 6 messages being
-sent to the server, and cause the data returned to be printed in some
-format. Most commands currently implemented send a single message and
-expect a single response. The current exceptions are the
+assigned to it. NTP control messages which carry peer variables
+must identify the peer the values correspond to by including
+its association ID. An association ID of 0 is special, and indicates
+the variables are system variables, whose names are drawn from a
+separate name space.
+.PP
+Control message commands result in one or more NTP mode 6
+messages being sent to the server, and cause the data returned to be
+printed in some format. Most commands currently implemented send a single
+message and expect a single response. The current exceptions are the
.B peers
command, which will send a preprogrammed series of messages to obtain
the data it needs, and the
@@ -313,53 +313,57 @@ commands, which will iterate over a range of associations.
.PP
.B associations
.PP
-Obtains and prints a list of association identifiers and peer statuses
-for in\-spec peers of the server being queried. The list is printed in
-columns. The first of these is an index numbering the associations from
-1 for internal use, the second the actual association identifier
-returned by the server and the third the status word for the peer. This
+Obtains and prints a list of association identifiers and
+peer statuses for in\-spec
+peers of the server being queried. The list is printed in
+columns. The first of these is an index numbering the associations
+from 1 for internal use, the second the actual association identifier
+returned by the server and the third the status word for the peer. This
is followed by a number of columns containing data decoded from the
-status word. Note that the data returned by the \*(L"associations\*(R"
-command is cached internally in
+status word. Note
+that the data returned by the \*(L"associations\*(R" command is cached
+internally in
.IR ntpq .
The index is then of use when dealing with stupid servers which use
-association identifiers which are hard for humans to type, in that for
-any subsequent commands which require an association identifier as an
-argument, the form
+association identifiers which are hard for humans to type, in that
+for any subsequent commands which require an association identifier
+as an argument, the form
.I &index
may be used as an alternative.
.PP
.B lassocations
.PP
Obtains and prints a list of association identifiers and peer statuses
-for all associations for which the server is maintaining state. This
-command differs from the \*(L"associations\*(R" command only for servers
-which retain state for out\-of\-spec client associations (i.e.
-fuzzballs). Such associations are normally omitted from the display when
-the \*(L"associations\*(R" command is used, but are included in the
-output of \*(L"lassociations\*(R".
+for all associations for which the server is maintaining state. This
+command differs from the
+\*(L"associations\*(R"
+command only for servers which retain state for out\-of\-spec client
+associations (i.e. fuzzballs). Such associations are normally omitted
+from the display when the
+\*(L"associations\*(R"
+command is used, but are included in the output of
+\*(L"lassociations\*(R".
.PP
.B passociations
.PP
-Prints association data concerning in\-spec peers from the internally
-cached list of associations. This command performs identically to the
-\*(L"associations\*(R" except that it displays the internally stored
-data rather than making a new query.
+Prints association data concerning in\-spec peers from the internally cached
+list of associations. This command performs
+identically to the \*(L"associations\*(R" except that it displays the
+internally stored data rather than making a new query.
.PP
.B lpassociations
.PP
Print data for all associations, including out\-of\-spec client
-associations, from the internally cached list of associations. This
-command differs from \*(L"passociations\*(R" only when dealing with
-fuzzballs.
+associations, from the internally cached list of associations. This command
+differs from \*(L"passociations\*(R" only when dealing with fuzzballs.
.PP
.B pstatus
.I assocID
.PP
-Sends a read status request to the server for the given association. The
-names and values of the peer variables returned will be printed. Note
-that the status word from the header is displayed preceding the
-variables, both in hexidecimal and in pidgeon English.
+Sends a read status request to the server for the given association.
+The names and values of the peer variables returned will be printed. Note
+that the status word from the header is displayed preceding the variables,
+both in hexidecimal and in pidgeon English.
.PP
.B readvar
[
@@ -369,12 +373,13 @@ variables, both in hexidecimal and in pidgeon English.
]
.PP
Requests that the values of the specified variables be returned by the
-server by sending a read variables request. If the association ID is
-omitted or is given as zero the variables are system variables,
-otherwise they are peer variables and the values returned will be those
-of the corresponding peer. Omitting the variable list will send a
-request with no data which should induce the server to return a default
-display.
+server by sending a read variables request. If the association ID
+is omitted or is given as zero the variables
+are system variables, otherwise they
+are peer variables and the values returned will be those
+of the corresponding peer. Omitting the variable list will send a
+request with no data which should induce the server to return a
+default display.
.PP
.B rv
[
@@ -400,12 +405,12 @@ request, except the specified variables are written instead of read.
.I assocID
]
.PP
-Requests that the values of the variables in the internal variable list
-be returned by the server. If the association ID is omitted or is 0 the
-variables are assumed to be system variables. Otherwise they are treated
-as peer variables. If the internal variable list is empty a request is
-sent without data, which should induce the remote server to return a
-default display.
+Requests that the values of the variables in the internal variable
+list be returned by the server. If the association ID is omitted
+or is 0 the variables are assumed to be system variables. Otherwise
+they are treated as peer variables. If the internal variable list
+is empty a request is sent without data, which should induce the remote
+server to return a default display.
.PP
.B rl
[
@@ -423,7 +428,8 @@ command.
.PP
Like the
.B readlist
-request, except the internal list variables are written instead of read.
+request, except the internal list variables are written instead of
+read.
.PP
.B mreadvar
.I assocID
@@ -435,7 +441,7 @@ request, except the internal list variables are written instead of read.
Like the
.B readvar
command except the query is done for each of a range of (nonzero)
-association IDs. This range is determined from the association list
+association IDs. This range is determined from the association list
cached by the most recent
.B associations
command.
@@ -458,7 +464,7 @@ command.
Like the
.B readlist
command except the query is done for each of a range of (nonzero)
-association IDs. This range is determined from the association list
+association IDs. This range is determined from the association list
cached by the most recent
.B associations
command.
@@ -479,16 +485,15 @@ command.
.IR <variable_name>[=<value>] [,...]
]
.PP
-Requests that a list of the server's clock variables be sent. Servers
+Requests that a list of the server's clock variables be sent. Servers
which have a radio clock or other external synchronization will respond
-positively to this. If the association identifier is omitted or zero the
-request is for the variables of the \*(L"system clock\*(R" and will
-generally get a positive response from all servers with a clock. If the
-server treats clocks as pseudo\-peers, and hence can possibly have more
-than one clock connected at once, referencing the appropriate peer
-association ID will show the variables of a particular clock. Omitting
-the variable list will cause the server to return a default variable
-display.
+positively to this. If the association identifier is omitted or zero
+the request is for the variables of the \*(L"system clock\*(R" and will
+generally get a positive response from all servers with a clock. If the
+server treats clocks as pseudo\-peers, and hence can possibly have more than
+one clock connected at once, referencing the appropriate
+peer association ID will show the variables of a particular clock. Omitting
+the variable list will cause the server to return a default variable display.
.PP
.B cv
[
@@ -504,42 +509,40 @@ command.
.PP
.B peers
.PP
-Obtains a list of in\-spec peers of the server, along with a summary of
-each peer's state. Summary information includes the address of the
-remote peer, the reference ID (0.0.0.0 if the refID is unknown), the
-stratum of the remote peer, the type of the peer (local, unicast,
-multicast or broadcast), when the last packet was received, the polling
-interval, in seconds, the reachability register, in octal, and the
-current estimated delay, offset and dispersion of the peer, all in
-seconds.
+Obtains a list of in\-spec peers of the server, along
+with a summary of each peer's state. Summary information includes the address
+of the remote peer, the reference ID (0.0.0.0 if the refID is unknown),
+the stratum of the remote peer, the polling interval,
+in seconds, the reachability
+register, in octal, and the current estimated delay, offset and dispersion
+of the peer, all in seconds.
.PP
The character in the left margin indicates the fate of this peer in the
-clock selection process. The codes mean: <sp> discarded due to high
-stratum and/or failed sanity checks; \*(L"x\*(R" designated falsticker
-by the intersection algorithm; \*(L".\*(R" culled from the end of the
-candidate list; \*(L"-\*(R" discarded by the clustering algorithmi;
-\*(L"+\*(R" included in the final selection set; \*(L"#\*(R" selected
-for synchronizatio;n but distance exceeds maximum; \*(L"*\*(R" selected
-for synchronization; and \*(L"o\*(R" selected for synchronization, pps
-signal in use.
+clock selection process. The codes mean: <sp> discarded due to high stratum
+and/or failed sanity checks; \*(L"x\*(R" designated falsticker by the
+intersection algorithm; \*(L".\*(R" culled from the end of the candidate
+list; \*(L"-\*(R" discarded by the clustering algorithmi; \*(L"+\*(R"
+included in the final selection set; \*(L"#\*(R" selected for synchronizatio;n
+but distance exceeds maximum; \*(L"*\*(R" selected for synchronization; and
+\*(L"o\*(R" selected for synchronization, pps signal in use.
.PP
Note that since the
.B peers
-command depends on the ability to parse the values in the responses it
-gets it may fail to work from time to time with servers which poorly
-control the data formats.
+command depends on the ability to parse the values in the
+responses it gets it may fail to work from time to time with servers
+which poorly control the data formats.
.PP
-The contents of the host field may be one of four forms. It may be a
-host name, an IP address, a reference clock implementation name with its
-parameter or \*(L"REFCLK(<implementation number>, <parameter>)\*(R". On
-\*(L"hostnames no\*(R" only IP\-addresses will be displayed.
+The contents of the host field may be one of four forms. It may be a host name,
+an IP address, a reference clock implementation name with its parameter or
+\*(L"REFCLK(<implementation number>, <parameter>)\*(R". On \*(L"hostnames no\*(R"
+only IP\-addresses will be displayed.
.PP
.B lpeers
.PP
Like
.BR peers ,
except a summary of all associations for which the server is maintaining
-state is printed. This can produce a much longer list of peers from
+state is printed. This can produce a much longer list of peers from
fuzzball servers.
.PP
.B opeers
@@ -554,10 +557,10 @@ Written by Dennis Ferguson at the University of Toronto.
The
.B peers
command is non\-atomic and may occasionally result in spurious error
-messages about invalid associations occuring and terminating the
+messages about invalid associations occurring and terminating the
command.
.PP
The timeout time is a fixed constant, which means you wait a long time
-for time outs since it assumes sort of a worst case. The program should
-improve the time out estimate as it sends queries to a particular host,
-but doesn't.
+for time outs since it assumes sort of a worst case. The program
+should improve the time out estimate as it sends queries to a particular
+host, but doesn't.
diff --git a/usr.sbin/xntpd/include/ntp_machine.h b/usr.sbin/xntpd/include/ntp_machine.h
index 91c18dc..16c3fbf 100644
--- a/usr.sbin/xntpd/include/ntp_machine.h
+++ b/usr.sbin/xntpd/include/ntp_machine.h
@@ -1,4 +1,4 @@
-/*
+/* ntp_machine.h,v 3.1 1993/07/06 01:06:49 jbj Exp
* Collect all machine dependent idiosyncrasies in one place.
*/
@@ -84,6 +84,7 @@ INFO ON NEW KERNEL PLL SYS CALLS
NTP_SYSCALLS_STD - use the "normal" ones
NTP_SYSCALL_GET - SYS_ntp_gettime id
NTP_SYSCALL_ADJ - SYS_ntp_adjtime id
+ NTP_SYSCALLS_LIBC - ntp_adjtime() and ntp_gettime() are in libc.
HOW TO GET IP INTERFACE INFORMATION
@@ -180,7 +181,6 @@ in this file.
#define RETSIGTYPE void
#define NTP_SYSCALL_GET 132
#define NTP_SYSCALL_ADJ 147
-#define HAVE_MODEM_CONTROL
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/SunOS 4.x"
#endif
@@ -219,7 +219,6 @@ in this file.
#define HAVE_ATT_SETPGRP
#define HAVE_ATT_NICE
#define UDP_WILDCARD_DELIVERY
-#define HAVE_MODEM_CONTROL
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/Solaris 2.x"
#endif
@@ -278,7 +277,6 @@ in this file.
#define HAVE_BSD_NICE
#define RETSIGTYPE void
#define NTP_SYSCALLS_STD
-#define HAVE_MODEM_CONTROL
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/Ultrix"
#endif
@@ -367,19 +365,6 @@ in this file.
#endif
/*
- * 4.4 bsd
- */
-#if defined(SYS_44BSD)
-#define HAVE_SIGNALED_IO
-#define HAVE_LIBKVM
-#define NTP_POSIX_SOURCE
-#define HAVE_BSD_NICE
-#ifndef STR_SYSTEM
-#define STR_SYSTEM "UNIX/4.4BSD"
-#endif
-#endif
-
-/*
* Linux
*/
#if defined(SYS_LINUX)
@@ -407,9 +392,16 @@ in this file.
#define NTP_POSIX_SOURCE
#define HAVE_BSD_NICE
#ifndef STR_SYSTEM
-#define STR_SYSTEM "UNIX/\052BSD"
+#define STR_SYSTEM "UNIX/*BSD"
#endif
#endif
+#ifdef SYS_FREEBSD
+#define HAVE_TERMIOS
+#define HAVE_UNAME
+#define HAVE_SYS_TIMEX_H
+#define NTP_SYSCALLS_LIBC
+#define KERNEL_PLL
+#endif
/*
* DEC AXP OSF/1
@@ -420,42 +412,12 @@ in this file.
#define NTP_POSIX_SOURCE
#define NTP_SYSCALLS_STD
#define HAVE_BSD_NICE
-#define HAVE_MODEM_CONTROL
#ifndef STR_SYSTEM
#define STR_SYSTEM "UNIX/DECOSF1"
#endif
#endif
/*
- * Intel x86 OSF/1
- */
-#if defined(SYS_IX86OSF1)
-#define HAVE_SIGNALED_IO
-#define HAVE_READKMEM
-#define NTP_POSIX_SOURCE
-#define NTP_SYSCALLS_STD
-#define HAVE_BSD_NICE
-#define HAVE_MODEM_CONTROL
-#define SYS_DECOSF1
-#ifndef STR_SYSTEM
-#define STR_SYSTEM "UNIX/IX86OSF1"
-#endif
-#endif
-
-/*
- * ISI
- */
-#if defined(SYS_BSD)
-#define NO_SIGNED_CHAR_DECL
-#define HAVE_BSD_NICE
-#define HAVE_BSD_TTYS
-#define HAVE_READKMEM
-#define HAVE_SIGNALED_IO
-#define NEED_VSPRINTF
-#undef NTP_POSIX_SOURCE
-#endif
-
-/*
* I386
* XXX - what OS?
*/
diff --git a/usr.sbin/xntpd/lib/Makefile b/usr.sbin/xntpd/lib/Makefile
new file mode 100644
index 0000000..a58c52f
--- /dev/null
+++ b/usr.sbin/xntpd/lib/Makefile
@@ -0,0 +1,30 @@
+#
+# $Id: Makefile,v 1.4 1993/12/22 11:32:23 rgrimes Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+SRCS= atoint.c atolfp.c atouint.c auth12crypt.c authdecrypt.c authdes.c \
+ authencrypt.c authkeys.c authparity.c authreadkeys.c authusekey.c \
+ buftvtots.c caljulian.c calleapwhen.c caltontp.c calyearstart.c \
+ clocktime.c dofptoa.c dolfptoa.c emalloc.c fptoa.c fptoms.c \
+ gettstamp.c hextoint.c hextolfp.c humandate.c inttoa.c \
+ lib_strbuf.c mfptoa.c mfptoms.c modetoa.c mstolfp.c \
+ msutotsf.c netof.c numtoa.c refnumtoa.c numtohost.c octtoint.c \
+ prettydate.c ranny.c tsftomsu.c tstotv.c tvtoa.c tvtots.c \
+ uglydate.c uinttoa.c utvtoa.c clocktypes.c \
+ md5.c a_md5encrypt.c a_md5decrypt.c \
+ a_md512crypt.c decodenetnum.c systime.c msyslog.c syssignal.c \
+ findconfig.c getopt.c
+
+NOMAN=
+NOPROFILE=
+LIB= ntp
+CLEANFILES+=authdes.c
+
+install:
+
+authdes.c: authdes.c.export
+ cp ${.CURDIR}/authdes.c.export authdes.c
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/xntpd/lib/authdes.c.export b/usr.sbin/xntpd/lib/authdes.c.export
index cb311f9..a63c6d3 100644
--- a/usr.sbin/xntpd/lib/authdes.c.export
+++ b/usr.sbin/xntpd/lib/authdes.c.export
@@ -1,4 +1,4 @@
-/*
+/* authdes.c.export,v 3.1 1993/07/06 01:07:48 jbj Exp
* authdes.c - dummy encryption routines for destinations outside the USA.
*
* Sorry, folks; I hate this, too. Send me your e-mail address in an
diff --git a/usr.sbin/xntpd/lib/msyslog.c b/usr.sbin/xntpd/lib/msyslog.c
index b1c8e0d..a637e50 100644
--- a/usr.sbin/xntpd/lib/msyslog.c
+++ b/usr.sbin/xntpd/lib/msyslog.c
@@ -1,4 +1,4 @@
-/*
+/* msyslog.c,v 3.1 1993/07/06 01:08:36 jbj Exp
* msyslog - either send a message to the terminal or print it on
* the standard output.
*
@@ -43,11 +43,11 @@ void msyslog(va_alist)
char *fmt;
#endif
va_list ap;
- char buf[1025], nfmt[256], xerr[50], *err;
+ char buf[1025], nfmt[256], xerr[50];
+ const char *err;
register int c, l;
register char *n, *f, *prog;
extern int sys_nerr;
- extern char *sys_errlist[];
int olderrno;
#ifdef __STDC__
@@ -73,7 +73,7 @@ void msyslog(va_alist)
continue;
}
if ((unsigned)olderrno > sys_nerr)
- sprintf((err = xerr), "error %d", olderrno);
+ sprintf((char *)(err = xerr), "error %d", olderrno);
else
err = sys_errlist[olderrno];
if (n + (l = strlen(err)) < &nfmt[254]) {
diff --git a/usr.sbin/xntpd/machines/hpux10+ b/usr.sbin/xntpd/machines/hpux10+
new file mode 100644
index 0000000..0119b63
--- /dev/null
+++ b/usr.sbin/xntpd/machines/hpux10+
@@ -0,0 +1,8 @@
+SHELL= /bin/sh
+RANLIB= ls # ar does the work of ranlib under System V
+DEFS_LOCAL= -DREFCLOCK
+DEFS= -DHAVE_TERMIOS -DSYS_HPUX=10
+AUTHDEFS= -DDES -DMD5
+CLOCKDEFS= -DLOCAL_CLOCK
+COPTS=
+INSTALL=$(TOP)scripts/install.sh
diff --git a/usr.sbin/xntpd/ntpdate/Makefile b/usr.sbin/xntpd/ntpdate/Makefile
new file mode 100644
index 0000000..3a1b68b
--- /dev/null
+++ b/usr.sbin/xntpd/ntpdate/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.2 1993/12/21 21:06:30 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntpdate
+MAN8= ${.CURDIR}/../doc/ntpdate.8
+CLEANFILES+= .version version.c
+
+SRCS= ntpdate.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntpdate
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/ntpq/Makefile b/usr.sbin/xntpd/ntpq/Makefile
new file mode 100644
index 0000000..4fc41c4
--- /dev/null
+++ b/usr.sbin/xntpd/ntpq/Makefile
@@ -0,0 +1,29 @@
+#
+# $Id: Makefile,v 1.2 1993/12/21 21:06:32 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntpq
+MAN8= ${.CURDIR}/../doc/ntpq.8
+CLEANFILES+= .version version.c
+BINDIR= /usr/bin
+
+SRCS= ntpq.c ntpq_ops.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntpq
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/ntpq/ntpq.c b/usr.sbin/xntpd/ntpq/ntpq.c
index 441b283..73c2a35 100644
--- a/usr.sbin/xntpd/ntpq/ntpq.c
+++ b/usr.sbin/xntpd/ntpq/ntpq.c
@@ -1,4 +1,4 @@
-/*
+/* ntpq.c,v 3.1 1993/07/06 01:09:29 jbj Exp
* ntpq - query an NTP server using mode 6 commands
*/
#include <stdio.h>
@@ -27,7 +27,7 @@ char *prompt = "ntpq> "; /* prompt to ask him about */
/*
* Keyid used for authenticated requests. Obtained on the fly.
*/
-u_long info_auth_keyid = -1;
+U_LONG info_auth_keyid = -1;
/*
* Type of key md5 or des
@@ -88,7 +88,7 @@ struct ctl_var sys_var[] = {
{ CS_LEAP, LP, "leap" }, /* 1 */
{ CS_STRATUM, UI, "stratum" }, /* 2 */
{ CS_PRECISION, IN, "precision" }, /* 3 */
- { CS_ROOTDELAY, FS, "rootdelay" }, /* 4 */
+ { CS_ROOTDELAY, FU, "rootdelay" }, /* 4 */
{ CS_ROOTDISPERSION, FU, "rootdispersion" }, /* 5 */
{ CS_REFID, RF, "refid" }, /* 6 */
{ CS_REFTIME, TS, "reftime" }, /* 7 */
@@ -96,7 +96,7 @@ struct ctl_var sys_var[] = {
{ CS_PEERID, UI, "peer" }, /* 9 */
{ CS_OFFSET, FL, "phase" }, /* 10 */
{ CS_DRIFT, FS, "freq" }, /* 11 */
- { CS_COMPLIANCE, FU, "error" }, /* 12 */
+ { CS_COMPLIANCE, UI, "compliance" }, /* 12 */
{ CS_CLOCK, TS, "clock" }, /* 13 */
{ CS_LEAPIND, LP, "leapindicator" }, /* 14 */
{ CS_LEAPWARNING, LP, "leapwarning" }, /* 15 */
@@ -149,7 +149,7 @@ struct ctl_var peer_var[] = {
{ CP_FLASH, TST, "flash"}, /* 34 */
{ CP_DISP, AR, "disp" }, /* 35 */
/*
- * These are duplicate entries so that we can
+ * These are duplicate entires so that we can
* process deviant version of the xntp protocal.
*/
{ CP_SRCADR, HA, "peeraddr" }, /* 4 */
@@ -173,8 +173,8 @@ struct ctl_var clock_var[] = {
{ CC_BADDATA, UI, "baddata" }, /* 6 */
{ CC_FUDGETIME1, FL, "fudgetime1" }, /* 7 */
{ CC_FUDGETIME2, FL, "fudgetime2" }, /* 8 */
- { CC_FUDGEVAL1, UI, "stratum" }, /* 9 */
- { CC_FUDGEVAL2, RF, "refid" }, /* 10 */
+ { CC_FUDGEVAL1, IN, "fudgeval1" }, /* 9 */
+ { CC_FUDGEVAL2, IN, "fudgeval2" }, /* 10 */
{ CC_FLAGS, UI, "flags" }, /* 11 */
{ CC_DEVICE, ST, "device" }, /* 12 */
{ 0, EOV, "" }
@@ -308,6 +308,11 @@ static void tokenize P((char *, char **, int *));
static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
static int getarg P((char *, int, arg_v *));
static int rtdatetolfp P((char *, l_fp *));
+
+#ifdef UNUSED
+static int decodereach P((char *, U_LONG *));
+#endif /* UNUSED */
+
static int decodearr P((char *, int *, l_fp *));
static char * getcode P((int, struct codestring *));
static void help P((struct parse *, FILE *));
@@ -334,7 +339,7 @@ static void authenticate P((struct parse *, FILE *));
static void ntpversion P((struct parse *, FILE *));
static void warning P((char *, char *, char *));
static void error P((char *, char *, char *));
-static u_long getkeyid P((char *));
+static U_LONG getkeyid P((char *));
static void atoascii P((int, char *, char *));
static void makeascii P((int, char *, FILE *));
static char * getevents P((int));
@@ -419,7 +424,7 @@ struct xcmd builtins[] = {
#define DEFSTIMEOUT (2) /* 2 second time out after first */
#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
#define DEFHOST "localhost" /* default host name */
-#define LENHOSTNAME 256 /* host name is 256 characters long */
+#define LENHOSTNAME 256 /* host name is 256 characters LONG */
#define MAXCMDS 100 /* maximum commands on cmd line */
#define MAXHOSTS 100 /* maximum hosts on cmd line */
#define MAXLINE 512 /* maximum line length */
@@ -449,12 +454,12 @@ struct servent *server_entry = NULL; /* server entry for ntp */
u_short sequence;
/*
- * Holds data returned from queries. Declare buffer long to be sure of
+ * Holds data returned from queries. Declare buffer LONG to be sure of
* alignment.
*/
#define MAXFRAGS 24 /* maximum number of fragments */
#define DATASIZE (MAXFRAGS*480) /* maximum amount of data */
-long pktdata[DATASIZE/sizeof(long)];
+LONG pktdata[DATASIZE/sizeof(LONG)];
/*
* Holds association data for use with the &n operator.
@@ -592,7 +597,7 @@ static int
openhost(hname)
char *hname;
{
- u_long netnum;
+ U_LONG netnum;
char temphost[LENHOSTNAME];
if (server_entry == NULL) {
@@ -707,9 +712,9 @@ getresponse(opcode, associd, rstatus, rsize, rdata, timeo)
/*
* This is pretty tricky. We may get between 1 and MAXFRAG packets
* back in response to the request. We peel the data out of
- * each packet and collect it in one long block. When the last
+ * each packet and collect it in one LONG block. When the last
* packet in the sequence is received we'll know how much data we
- * should have had. Note we use one long time out, should reconsider.
+ * should have had. Note we use one LONG time out, should reconsider.
*/
*rsize = 0;
if (rstatus)
@@ -874,8 +879,8 @@ again:
if (debug >= 3) {
int shouldbesize;
- u_long key;
- u_long *lpkt;
+ U_LONG key;
+ U_LONG *lpkt;
int maclen;
/*
@@ -893,15 +898,15 @@ again:
printf(
"Packet shows signs of authentication (total %d, data %d, mac %d)\n",
n, shouldbesize, maclen);
- lpkt = (u_long *)&rpkt;
+ lpkt = (U_LONG *)&rpkt;
printf("%08lx %08lx %08lx %08lx %08lx %08lx\n",
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 3]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 2]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) - 1]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long)]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 1]),
- (u_long)ntohl(lpkt[(n - maclen)/sizeof(u_long) + 2]));
- key = ntohl(lpkt[(n - maclen) / sizeof(u_long)]);
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 3]),
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 2]),
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG) - 1]),
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG)]),
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG) + 1]),
+ ntohl(lpkt[(n - maclen)/sizeof(U_LONG) + 2]));
+ key = ntohl(lpkt[(n - maclen) / sizeof(U_LONG)]);
printf("Authenticated with keyid %lu\n", key);
if (key != 0 && key != info_auth_keyid) {
printf("We don't know that key\n");
@@ -1062,7 +1067,7 @@ sendrequest(opcode, associd, auth, qsize, qdata)
if (qsize > 0) {
memmove((char *)qpkt.data, qdata, qsize);
pktsize = qsize + CTL_HEADER_LEN;
- while (pktsize & (sizeof(u_long) - 1)) {
+ while (pktsize & (sizeof(U_LONG)-1)) {
qpkt.data[qsize++] = 0;
pktsize++;
}
@@ -1113,7 +1118,7 @@ sendrequest(opcode, associd, auth, qsize, qdata)
* cp currently points. Cp should be aligned
* properly. Then do the encryptions.
*/
- *(u_long *)(&qpkt.data[qsize]) = htonl(info_auth_keyid);
+ *(U_LONG *)(&qpkt.data[qsize]) = htonl(info_auth_keyid);
maclen = authencrypt(info_auth_keyid, (U_LONG *)&qpkt,
pktsize);
return sendpkt((char *)&qpkt, pktsize + maclen);
@@ -1537,22 +1542,21 @@ getarg(str, code, argp)
int
getnetnum(host, num, fullhost)
char *host;
- u_long *num;
+ U_LONG *num;
char *fullhost;
{
struct hostent *hp;
if (decodenetnum(host, num)) {
if (fullhost != 0) {
- (void) sprintf(fullhost, "%lu.%lu.%lu.%lu",
- (u_long)((htonl(*num) >> 24) & 0xff),
- (u_long)((htonl(*num) >> 16) & 0xff),
- (u_long)((htonl(*num) >> 8) & 0xff),
- (u_long)(htonl(*num) & 0xff));
+ (void) sprintf(fullhost,
+ "%d.%d.%d.%d", ((htonl(*num)>>24)&0xff),
+ ((htonl(*num)>>16)&0xff), ((htonl(*num)>>8)&0xff),
+ (htonl(*num)&0xff));
}
return 1;
} else if ((hp = gethostbyname(host)) != 0) {
- memmove((char *)num, hp->h_addr, sizeof(u_long));
+ memmove((char *)num, hp->h_addr, sizeof(U_LONG));
if (fullhost != 0)
(void) strcpy(fullhost, hp->h_name);
return 1;
@@ -1569,7 +1573,7 @@ getnetnum(host, num, fullhost)
*/
char *
nntohost(netnum)
- u_long netnum;
+ U_LONG netnum;
{
if (!showhostnames)
return numtoa(netnum);
@@ -1609,7 +1613,7 @@ rtdatetolfp(str, lfp)
/*
* Catch special case
*/
- L_CLR(lfp);
+ lfp->l_ui = lfp->l_uf = 0;
return 1;
}
return 0;
@@ -1650,7 +1654,7 @@ rtdatetolfp(str, lfp)
* Catch special case. If cal.year == 0 this is a zero timestamp.
*/
if (cal.year == 0) {
- L_CLR(lfp);
+ lfp->l_ui = lfp->l_uf = 0;
return 1;
}
@@ -1744,18 +1748,49 @@ decodetime(str, lfp)
}
+#ifdef UNUSED
+/*
+ * decodereach - decode a (possibly octal or hex, damn fuzzballs) reachability
+ */
+static int
+decodereach(str, uval)
+ char *str;
+ U_LONG *uval;
+{
+ U_LONG u;
+
+ if (*str == '0') {
+ /*
+ * Could be octal or hex
+ */
+ if (*(str+1) == 'x' || *(str+1) == 'X')
+ return hextoint(str+2, uval);
+ return octtoint(str, uval);
+ }
+
+ if (!atouint(str, &u))
+ return 0;
+
+ if (u > 255)
+ return octtoint(str, uval);
+ *uval = u;
+ return 1;
+}
+#endif /* UNUSED */
+
+
/*
* decodeint - decode an integer
*/
int
decodeint(str, val)
char *str;
- long *val;
+ LONG *val;
{
if (*str == '0') {
if (*(str+1) == 'x' || *(str+1) == 'X')
- return hextoint(str+2, (u_long *)&val);
- return octtoint(str, (u_long *)&val);
+ return hextoint(str+2, (U_LONG *)val);
+ return octtoint(str, (U_LONG *)val);
}
return atoint(str, val);
}
@@ -1767,7 +1802,7 @@ decodeint(str, val)
int
decodeuint(str, val)
char *str;
- u_long *val;
+ U_LONG *val;
{
if (*str == '0') {
if (*(str+1) == 'x' || *(str+1) == 'X')
@@ -1982,18 +2017,18 @@ delay(pcmd, fp)
FILE *fp;
{
int isneg;
- u_long val;
+ U_LONG val;
if (pcmd->nargs == 0) {
val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
- (void) fprintf(fp, "delay %lu ms\n", val);
+ (void) fprintf(fp, "delay %d ms\n", val);
} else {
if (pcmd->argval[0].ival < 0) {
isneg = 1;
- val = (u_long)(-pcmd->argval[0].ival);
+ val = (U_LONG)(-pcmd->argval[0].ival);
} else {
isneg = 0;
- val = (u_long)pcmd->argval[0].ival;
+ val = (U_LONG)pcmd->argval[0].ival;
}
delay_time.l_ui = val / 1000;
@@ -2057,7 +2092,7 @@ keyid(pcmd, fp)
if (info_auth_keyid == -1)
(void) fprintf(fp, "no keyid defined\n");
else
- (void) fprintf(fp, "keyid is %lu\n", info_auth_keyid);
+ (void) fprintf(fp, "keyid is %u\n", info_auth_keyid);
} else {
info_auth_keyid = pcmd->argval[0].uval;
}
@@ -2309,7 +2344,7 @@ error(fmt, st1, st2)
/*
* getkeyid - prompt the user for a keyid to use
*/
-static u_long
+static U_LONG
getkeyid(prompt)
char *prompt;
{
@@ -2333,7 +2368,7 @@ char *prompt;
if (strcmp(pbuf, "0") == 0)
return 0;
- return (u_long) atoi(pbuf);
+ return (U_LONG) atoi(pbuf);
}
@@ -2480,9 +2515,7 @@ statustoa(type, st)
case TYPE_SYS:
(void)strcpy(cb, getcode(CTL_SYS_LI(st), leap_codes));
(void)strcat(cb, ", ");
- (void)strcat(cb, getcode(CTL_SYS_SOURCE(st) & ~CTL_SST_TS_PPS, sync_codes));
- if (CTL_SYS_SOURCE(st) & CTL_SST_TS_PPS)
- (void)strcat(cb, "/PPS");
+ (void)strcat(cb, getcode(CTL_SYS_SOURCE(st), sync_codes));
(void)strcat(cb, ", ");
(void)strcat(cb, getevents(CTL_SYS_NEVNT(st)));
(void)strcat(cb, ", ");
@@ -2820,7 +2853,7 @@ outputarr(fp, name, narr, lfp)
static char *
tstflags(val)
- u_long val;
+ U_LONG val;
{
register char *cb, *s;
register int i;
@@ -2832,7 +2865,7 @@ tstflags(val)
if (++nextcb >= NUMCB)
nextcb = 0;
- sprintf(cb, "0x%lx", val);
+ sprintf(cb, "0x%x", val);
cb += strlen(cb);
if (val <= ((1<<8)-1)) {
if (!val) {
@@ -2876,9 +2909,8 @@ cookedprint(datatype, length, data, status, fp)
int fmt;
struct ctl_var *varlist;
l_fp lfp;
- long ival;
- u_long hval;
- u_long uval;
+ LONG ival;
+ U_LONG uval;
l_fp lfparr[8];
int narr;
@@ -2954,12 +2986,12 @@ cookedprint(datatype, length, data, status, fp)
case HA:
case NA:
- if (!decodenetnum(value, &hval))
+ if (!decodenetnum(value, &uval))
output_raw = '?';
else if (fmt == HA)
- output(fp, name, nntohost(hval));
+ output(fp, name, nntohost(uval));
else
- output(fp, name, numtoa(hval));
+ output(fp, name, numtoa(uval));
break;
case ST:
@@ -2967,8 +2999,8 @@ cookedprint(datatype, length, data, status, fp)
break;
case RF:
- if (decodenetnum(value, &hval))
- output(fp, name, nntohost(hval));
+ if (decodenetnum(value, &uval))
+ output(fp, name, nntohost(uval));
else if ((int)strlen(value) <= 4)
output(fp, name, value);
else
@@ -2996,7 +3028,7 @@ cookedprint(datatype, length, data, status, fp)
else {
char b[10];
- (void) sprintf(b, "%03lo", uval);
+ (void) sprintf(b, "%03o", uval);
output(fp, name, b);
}
break;
diff --git a/usr.sbin/xntpd/ntptrace/Makefile b/usr.sbin/xntpd/ntptrace/Makefile
new file mode 100644
index 0000000..57f3051
--- /dev/null
+++ b/usr.sbin/xntpd/ntptrace/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 19:50:40 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= ntptrace
+MAN8= ${.CURDIR}/../doc/ntptrace.8
+CLEANFILES+= .version version.c
+
+SRCS= ntptrace.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion ntptrace
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/parse/Makefile b/usr.sbin/xntpd/parse/Makefile
new file mode 100644
index 0000000..1a46fbe
--- /dev/null
+++ b/usr.sbin/xntpd/parse/Makefile
@@ -0,0 +1,19 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 19:42:18 wollman Exp $
+#
+
+PARSEFLAGS= -DCLOCK_SCHMID -DCLOCK_DCF7000 -DCLOCK_MEINBERG \
+ -DCLOCK_RAWDCF -DCLOCK_TRIMSV6
+
+CFLAGS+= -I${.CURDIR}/../include ${PARSEFLAGS}
+
+SRCS= parse.c parse_conf.c clk_meinberg.c clk_schmid.c clk_rawdcf.c \
+ clk_dcf7000.c clk_trimble.c
+
+NOMAN=
+NOPROFILE=
+LIB= parse
+
+install:
+
+.include <bsd.lib.mk>
diff --git a/usr.sbin/xntpd/parse/util/Makefile b/usr.sbin/xntpd/parse/util/Makefile
new file mode 100644
index 0000000..99caacf
--- /dev/null
+++ b/usr.sbin/xntpd/parse/util/Makefile
@@ -0,0 +1,49 @@
+#
+# /src/NTP/REPOSITORY/v3/parse/util/Makefile.tmpl,v 3.11 1993/11/17 13:34:12 kardel Exp
+#
+COMPILER= gcc
+DEFS= -DSYS_FREEBSD -DSYS_386BSD
+DEFS_OPT=-DDEBUG
+DEFS_LOCAL= $(DEFS_OPT) -DREFCLOCK -DPPSPPS -DKERNEL_PLL
+CLOCKDEFS= -DLOCAL_CLOCK -DAS2201PPS -DCHU -DGOES -DIRIG -DMX4200PPS -DOMEGA -DPSTCLK -DTPRO -DWWVBCLK -DMSFEESPPS -DLEITCH
+INCL=
+COPTS= -O2
+INSTALL= install
+BINDIR= /usr/local/bin
+#
+CFLAGS= $(COPTS) $(DEFS) $(DEFS_LOCAL) $(INCL) -I../../include
+CC= $(COMPILER)
+TOP=../../
+#
+EXECS=parsetest testdcf dcfd
+
+all:
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DSTREAM/ && /-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" parsetest"; } \
+ }' | \
+ sh
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" testdcf"; } \
+ }' | \
+ sh
+ @echo $(DEFS) $(DEFS_LOCAL) $(CLOCKDEFS) | \
+ awk '/-DPARSE/ && /-DCLOCK_RAWDCF/ && ( /-DSYS_SUNOS/ || /-DSYS_SOLARIS/ ) { makeit = 1 } \
+ END { if (makeit) \
+ { print "$(MAKE) $(MFLAGS) MFLAGS=\"$(MFLAGS)\" dcfd"; } \
+ }' | \
+ sh
+
+clean:
+ -@rm -f $(EXECS) *.o
+
+distclean: clean
+ -@rm -f *.orig *.rej .version Makefile
+
+install:
+ @echo "--- DCF77 utilities should be installed manually"
+ @#[ -f testdcf ] && $(INSTALL) -c -m 0755 testdcf $(BINDIR) || true
+ @#[ -f dcfd ] && $(INSTALL) -c -m 0755 dcfd $(BINDIR) || true
diff --git a/usr.sbin/xntpd/util/Makefile b/usr.sbin/xntpd/util/Makefile
new file mode 100644
index 0000000..ce9e1fd
--- /dev/null
+++ b/usr.sbin/xntpd/util/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 20:16:18 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= tickadj
+MAN8= ${.CURDIR}/../doc/tickadj.8
+CLEANFILES+= .version version.c
+
+SRCS= tickadj.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion tickadj
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/util/tickadj.c b/usr.sbin/xntpd/util/tickadj.c
index dc40fa7..dcf6935 100644
--- a/usr.sbin/xntpd/util/tickadj.c
+++ b/usr.sbin/xntpd/util/tickadj.c
@@ -7,12 +7,8 @@
*/
#include <stdio.h>
-#if !defined(SYS_VAX) && !defined(SYS_BSD)
-#include <unistd.h>
-#endif /* SYS_VAX */
-
#ifdef SYS_LINUX
-#include "sys/timex.h"
+#include <sys/timex.h>
struct timex txc;
@@ -46,9 +42,7 @@ main(int argc, char ** argv)
#else /* not Linux... kmem tweaking: */
#include <sys/types.h>
-#ifndef SYS_BSD
#include <sys/file.h>
-#endif
#include <sys/stat.h>
#if defined(SYS_AUX3) || defined(SYS_AUX2)
@@ -75,7 +69,7 @@ main(int argc, char ** argv)
#endif
#endif
-#if defined(SYS_PTX) || defined(SYS_IX86OSF1)
+#ifdef SYS_PTX
#define L_SET SEEK_SET
#endif
@@ -426,14 +420,16 @@ getoffsets(filex, tick_off, tickadj_off, dosync_off, noprintf_off)
{""},
};
#endif
- static char *kernels[] = {
+ char *kernels[] = {
+#if __FreeBSD__ > 1
+ (char *)getbootfile(),
+#endif
"/vmunix",
"/unix",
"/mach",
"/kernel/unix",
"/386bsd",
"/netbsd",
- "/hp-ux",
NULL
};
struct stat stbuf;
@@ -563,7 +559,7 @@ readvar(fd, off, var)
}
if (i != sizeof(int)) {
(void) fprintf(stderr, "%s: read expected %d, got %d\n",
- progname, (int)sizeof(int), i);
+ progname, sizeof(int), i);
exit(1);
}
}
diff --git a/usr.sbin/xntpd/xntpd/Makefile b/usr.sbin/xntpd/xntpd/Makefile
new file mode 100644
index 0000000..b10d376
--- /dev/null
+++ b/usr.sbin/xntpd/xntpd/Makefile
@@ -0,0 +1,45 @@
+#
+# $Id: Makefile,v 1.4 1994/02/03 23:23:17 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= ${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= ${.CURDIR}/../lib/libntp.a
+.endif
+
+.if exists(${.CURDIR}/../parse/obj)
+LDADD+= -L${.CURDIR}/../parse/obj
+DPADD+= ${.CURDIR}/../parse/obj/libparse.a
+.else
+LDADD+= -L${.CURDIR}/../parse
+DPADD+= ${.CURDIR}/../parse/libparse.a
+.endif
+
+LDADD+= -lntp -lparse
+
+PROG= xntpd
+MAN8= ${.CURDIR}/../doc/xntpd.8
+CLEANFILES+= .version version.c
+
+SRCS= ntp_config.c ntp_control.c ntp_io.c ntp_leap.c \
+ ntp_loopfilter.c ntp_monitor.c ntp_peer.c ntp_proto.c \
+ ntp_refclock.c ntp_request.c ntp_restrict.c ntp_timer.c \
+ ntp_unixclock.c ntp_util.c ntpd.c refclock_chu.c \
+ refclock_conf.c refclock_local.c refclock_pst.c \
+ refclock_wwvb.c refclock_goes.c refclock_mx4200.c \
+ refclock_parse.c refclock_as2201.c refclock_omega.c \
+ refclock_tpro.c refclock_leitch.c refclock_irig.c \
+ refclock_msfees.c refclock_gpstm.c refclock_trak.c ntp_intres.c \
+ ntp_filegen.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpd
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/xntpd/ntp_control.c b/usr.sbin/xntpd/xntpd/ntp_control.c
index 0f1dc2b..ef9c37a 100644
--- a/usr.sbin/xntpd/xntpd/ntp_control.c
+++ b/usr.sbin/xntpd/xntpd/ntp_control.c
@@ -3,12 +3,11 @@
*/
#include <stdio.h>
#include <ctype.h>
-#include <sys/types.h>
#include <signal.h>
+#include <sys/types.h>
#include <sys/time.h>
#include "ntpd.h"
-#include "ntp_io.h"
#include "ntp_refclock.h"
#include "ntp_control.h"
#include "ntp_stdlib.h"
@@ -42,13 +41,18 @@ static void ctl_flushpkt P((int));
static void ctl_putdata P((char *, int, int));
static void ctl_putstr P((char *, char *, int));
static void ctl_putlfp P((char *, l_fp *));
+
+#ifdef UNUSED
+static void ctl_putulfp P((char *, l_fp *));
+#endif /* UNUSED */
+
static void ctl_putfp P((char *, s_fp));
static void ctl_putufp P((char *, u_fp));
-static void ctl_putuint P((char *, u_long));
-static void ctl_puthex P((char *, u_long));
-static void ctl_putint P((char *, long));
+static void ctl_putuint P((char *, U_LONG));
+static void ctl_puthex P((char *, U_LONG));
+static void ctl_putint P((char *, LONG));
static void ctl_putts P((char *, l_fp *));
-static void ctl_putadr P((char *, u_long));
+static void ctl_putadr P((char *, U_LONG));
static void ctl_putid P((char *, char *));
static void ctl_putarray P((char *, s_fp *, int));
static void ctl_putsys P((int));
@@ -57,7 +61,7 @@ static void ctl_putpeer P((int, struct peer *));
static void ctl_putclock P((int, struct refclockstat *, int));
#endif /* REFCLOCK */
static struct ctl_var *ctl_getitem P((struct ctl_var *, char **));
-static u_long count_var P((struct ctl_var *));
+static unsigned long count_var P((struct ctl_var *));
static void control_unspec P((struct recvbuf *, int));
static void read_status P((struct recvbuf *, int));
static void read_variables P((struct recvbuf *, int));
@@ -97,7 +101,7 @@ static struct ctl_var sys_var[] = {
{ CS_PEERID, RO, "peer" }, /* 9 */
{ CS_OFFSET, RO, "phase" }, /* 10 */
{ CS_DRIFT, RO, "freq" }, /* 11 */
- { CS_COMPLIANCE, RO, "error" }, /* 12 */
+ { CS_COMPLIANCE, RO, "compliance" }, /* 12 */
{ CS_CLOCK, RO, "clock" }, /* 13 */
{ CS_LEAPIND, RW, "leapindicator" }, /* 14 */
{ CS_LEAPWARNING, RW, "leapwarning" }, /* 15 */
@@ -227,8 +231,8 @@ static struct ctl_var clock_var[] = {
{ CC_BADDATA, RO, "baddata" }, /* 6 */
{ CC_FUDGETIME1, RO, "fudgetime1" }, /* 7 */
{ CC_FUDGETIME2, RO, "fudgetime2" }, /* 8 */
- { CC_FUDGEVAL1, RO, "stratum" }, /* 9 */
- { CC_FUDGEVAL2, RO, "refid" }, /* 10 */
+ { CC_FUDGEVAL1, RO, "fudgeval1" }, /* 9 */
+ { CC_FUDGEVAL2, RO, "fudgeval2" }, /* 10 */
{ CC_FLAGS, RO, "flags" }, /* 11 */
{ CC_DEVICE, RO, "device" }, /* 12 */
{ CC_VARLIST, RO, "clock_var_list" },/* 13 */
@@ -300,36 +304,30 @@ static struct utsname utsname;
* set peer->sstclktype to something different than CTL_SST_TS_UNSPEC.
*/
static u_char clocktypes[] = {
- CTL_SST_TS_NTP, /* REFCLK_NONE (0) */
- CTL_SST_TS_LOCAL, /* REFCLK_LOCALCLOCK (1) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK (2) */
- CTL_SST_TS_HF, /* REFCLK_WWV_PST (3) */
- CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM (4) */
- CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME (5) */
- CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK (6) */
- CTL_SST_TS_HF, /* REFCLK_CHU (7) */
+ CTL_SST_TS_NTP, /* REFCLK_NONE */
+ CTL_SST_TS_UNSPEC, /* REFCLK_LOCALCLOCK */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_TRAK */
+ CTL_SST_TS_HF, /* REFCLK_WWV_PST */
+ CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM */
+ CTL_SST_TS_UHF, /* REFCLK_GOES_TRUETIME */
+ CTL_SST_TS_UHF, /* REFCLK_GOES_TRAK */
+ CTL_SST_TS_HF, /* REFCLK_CHU */
CTL_SST_TS_LF, /* REFCLOCK_PARSE - default value - driver supplies actual value in peer->sstclktype */
- CTL_SST_TS_LF, /* REFCLK_GPS_MX4200 (9) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 (10) */
- CTL_SST_TS_LF, /* REFCLK_OMEGA_TRUETIME (11) */
- CTL_SST_TS_UHF, /* REFCLK_IRIG_TPRO (12) */
- CTL_SST_TS_ATOM, /* REFCLK_ATOM_LEITCH (13) */
- CTL_SST_TS_LF, /* REFCLK_MSF_EES (14) */
- CTL_SST_TS_UHF, /* REFCLK_GPSTM_TRUETIME (15) */
- CTL_SST_TS_UHF, /* REFCLK_IRIG_BANCOMM (16) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_DATU (17) */
- CTL_SST_TS_TELEPHONE, /* REFCLK_NIST_ACT (18) */
- CTL_SST_TS_HF, /* REFCLK_WWV_HEATH (19) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_NMEA (20) */
- CTL_SST_TS_UHF, /* REFCLK_GPS_MOTO (21) */
- CTL_SST_TS_ATOM /* REFCLK_ATOM_PPS (22) */
+ CTL_SST_TS_LF, /* REFCLK_WWVB_SPECTRACOM_HP */
+ CTL_SST_TS_UHF, /* REFCLK_GPS_AS2201 */
+ CTL_SST_TS_LF, /* REFCLK_OMEGA_TRUETIME */
+ CTL_SST_TS_UNSPEC, /* Future expansion */
+ CTL_SST_TS_UNSPEC, /* Future expansion */
+ CTL_SST_TS_UNSPEC, /* Future expansion */
+ CTL_SST_TS_UNSPEC /* Future expansion */
};
+
/*
* Keyid used for authenticating write requests.
*/
-u_long ctl_auth_keyid;
+U_LONG ctl_auth_keyid;
/*
* We keep track of the last error reported by the system internally
@@ -341,21 +339,21 @@ static u_char ctl_sys_num_events;
/*
* Statistic counters to keep track of requests and responses.
*/
-u_long ctltimereset; /* time stats reset */
-u_long numctlreq; /* number of requests we've received */
-u_long numctlbadpkts; /* number of bad control packets */
-u_long numctlresponses; /* number of resp packets sent with data */
-u_long numctlfrags; /* number of fragments sent */
-u_long numctlerrors; /* number of error responses sent */
-u_long numctltooshort; /* number of too short input packets */
-u_long numctlinputresp; /* number of responses on input */
-u_long numctlinputfrag; /* number of fragments on input */
-u_long numctlinputerr; /* number of input pkts with err bit set */
-u_long numctlbadoffset; /* number of input pkts with nonzero offset */
-u_long numctlbadversion; /* number of input pkts with unknown version */
-u_long numctldatatooshort; /* data too short for count */
-u_long numctlbadop; /* bad op code found in packet */
-u_long numasyncmsgs; /* number of async messages we've sent */
+U_LONG ctltimereset; /* time stats reset */
+U_LONG numctlreq; /* number of requests we've received */
+U_LONG numctlbadpkts; /* number of bad control packets */
+U_LONG numctlresponses; /* number of resp packets sent with data */
+U_LONG numctlfrags; /* number of fragments sent */
+U_LONG numctlerrors; /* number of error responses sent */
+U_LONG numctltooshort; /* number of too short input packets */
+U_LONG numctlinputresp; /* number of responses on input */
+U_LONG numctlinputfrag; /* number of fragments on input */
+U_LONG numctlinputerr; /* number of input pkts with err bit set */
+U_LONG numctlbadoffset; /* number of input pkts with nonzero offset */
+U_LONG numctlbadversion; /* number of input pkts with unknown version */
+U_LONG numctldatatooshort; /* data too short for count */
+U_LONG numctlbadop; /* bad op code found in packet */
+U_LONG numasyncmsgs; /* number of async messages we've sent */
/*
* Imported from the I/O module
@@ -370,7 +368,7 @@ extern int debug;
/*
* Imported from the timer module
*/
-extern u_long current_time;
+extern U_LONG current_time;
extern struct peer *assoc_hash[];
extern int pps_control; /* flag for 1-pps signal present */
@@ -382,7 +380,7 @@ extern u_char sys_stratum;
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
-extern u_long sys_refid;
+extern U_LONG sys_refid;
extern l_fp sys_reftime;
extern l_fp sys_refskew;
extern u_char sys_poll;
@@ -392,7 +390,7 @@ extern struct peer *sys_peer;
*/
extern l_fp last_offset;
extern s_fp drift_comp;
-extern u_fp sys_maxd;
+extern int time_constant;
extern int pll_control;
/*
* Imported from the leap module
@@ -421,7 +419,7 @@ static struct interface *lcl_inter;
static u_char res_authenticate;
static u_char res_authokay;
-static u_long res_keyid;
+static U_LONG res_keyid;
#define MAXDATALINELEN (72)
@@ -482,14 +480,14 @@ ctl_error(errcode)
if (res_authenticate) {
int maclen;
- *(u_long *)((u_char *)&rpkt + CTL_HEADER_LEN)
+ *(U_LONG *)((u_char *)&rpkt + CTL_HEADER_LEN)
= htonl(res_keyid);
maclen =
authencrypt(res_keyid, (U_LONG *)&rpkt, CTL_HEADER_LEN);
- sendpkt(rmt_addr, lcl_inter, -2, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
CTL_HEADER_LEN + maclen);
} else {
- sendpkt(rmt_addr, lcl_inter, -3, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
CTL_HEADER_LEN);
}
numctlerrors++;
@@ -598,17 +596,17 @@ process_control(rbufp, restrict)
properlen = (properlen + 7) & ~7;
- if ((rbufp->recv_length & (sizeof(u_long)-1)) == 0
+ if ((rbufp->recv_length & (sizeof(U_LONG)-1)) == 0
&& (maclen = (rbufp->recv_length - properlen)) >= MIN_MAC_LEN
&& maclen <= MAX_MAC_LEN) {
res_authenticate = 1;
- res_keyid = ntohl(*(u_long *)((u_char *)pkt + properlen));
+ res_keyid = ntohl(*(U_LONG *)((u_char *)pkt + properlen));
#ifdef DEBUG
if (debug >= 3)
printf(
- "recv_len %d, properlen %d, wants auth with keyid %ld, MAC length=%d\n",
+ "recv_len %d, properlen %d, wants auth with keyid %d, MAC length=%d\n",
rbufp->recv_length, properlen, res_keyid, maclen);
#endif
if (!authhavekey(res_keyid)) {
@@ -730,18 +728,15 @@ ctlsysstatus()
register u_char clock;
clock = CTL_SST_TS_UNSPEC;
- if (sys_peer != 0) {
- if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC) {
+ if (sys_peer != 0)
+ if (sys_peer->sstclktype != CTL_SST_TS_UNSPEC)
clock = sys_peer->sstclktype;
- if (pps_control)
- clock |= CTL_SST_TS_PPS;
- } else {
+ else {
if (sys_peer->refclktype < sizeof(clocktypes))
clock = clocktypes[sys_peer->refclktype];
if (pps_control)
clock |= CTL_SST_TS_PPS;
}
- }
return (u_short)CTL_SYS_STATUS(sys_leap, clock,
ctl_sys_num_events, ctl_sys_last_event);
}
@@ -793,7 +788,6 @@ ctl_flushpkt(more)
rpkt.sequence = htons(ctl_trap[i].tr_sequence);
sendpkt(&ctl_trap[i].tr_addr,
ctl_trap[i].tr_localaddr,
- -4,
(struct pkt *)&rpkt, sendlen);
if (!more)
ctl_trap[i].tr_sequence++;
@@ -814,14 +808,14 @@ ctl_flushpkt(more)
*datapt++ = '\0';
totlen++;
}
- *(u_long *)datapt = htonl(res_keyid);
+ *(U_LONG *)datapt = htonl(res_keyid);
maclen =
authencrypt(res_keyid, (U_LONG *)&rpkt, totlen);
- sendpkt(rmt_addr, lcl_inter, -5, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
totlen + maclen);
} else {
- sendpkt(rmt_addr, lcl_inter, -6, (struct pkt *)&rpkt,
+ sendpkt(rmt_addr, lcl_inter, (struct pkt *)&rpkt,
sendlen);
}
if (more)
@@ -941,6 +935,33 @@ ctl_putlfp(tag, ts)
}
+#ifdef UNUSED
+/*
+ * ctl_putlfp - write a tagged, unsigned l_fp into the response
+ */
+static void
+ctl_putulfp(tag, ts)
+ char *tag;
+ l_fp *ts;
+{
+ register char *cp, *cq;
+ char buffer[200];
+
+ cp = buffer;
+ cq = tag;
+ while (*cq != '\0')
+ *cp++ = *cq++;
+
+ *cp++ = '=';
+ cq = ulfptoms(ts, 3);
+ while (*cq != '\0')
+ *cp++ = *cq++;
+
+ ctl_putdata(buffer, cp - buffer, 0);
+}
+#endif /* UNUSED */
+
+
/*
* ctl_putfp - write a tagged s_fp number into the response
*/
@@ -997,7 +1018,7 @@ ctl_putufp(tag, ufp)
static void
ctl_putuint(tag, uval)
char *tag;
- u_long uval;
+ U_LONG uval;
{
register char *cp, *cq;
char buffer[200];
@@ -1008,7 +1029,7 @@ ctl_putuint(tag, uval)
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%lu", uval);
+ (void) sprintf(cp, "%u", uval);
while (*cp != '\0')
cp++;
@@ -1022,7 +1043,7 @@ ctl_putuint(tag, uval)
static void
ctl_puthex(tag, uval)
char *tag;
- u_long uval;
+ U_LONG uval;
{
register char *cp, *cq;
char buffer[200];
@@ -1047,7 +1068,7 @@ ctl_puthex(tag, uval)
static void
ctl_putint(tag, ival)
char *tag;
- long ival;
+ LONG ival;
{
register char *cp, *cq;
char buffer[200];
@@ -1058,7 +1079,7 @@ ctl_putint(tag, ival)
*cp++ = *cq++;
*cp++ = '=';
- (void) sprintf(cp, "%ld", ival);
+ (void) sprintf(cp, "%d", ival);
while (*cp != '\0')
cp++;
@@ -1098,7 +1119,7 @@ ctl_putts(tag, ts)
static void
ctl_putadr(tag, addr)
char *tag;
- u_long addr;
+ U_LONG addr;
{
register char *cp, *cq;
char buffer[200];
@@ -1204,13 +1225,13 @@ ctl_putsys(varid)
switch (varid) {
case CS_LEAP:
- ctl_putuint(sys_var[CS_LEAP].text, sys_leap);
+ ctl_putuint(sys_var[CS_LEAP].text, (U_LONG)sys_leap);
break;
case CS_STRATUM:
- ctl_putuint(sys_var[CS_STRATUM].text, sys_stratum);
+ ctl_putuint(sys_var[CS_STRATUM].text, (U_LONG)sys_stratum);
break;
case CS_PRECISION:
- ctl_putint(sys_var[CS_PRECISION].text, sys_precision);
+ ctl_putint(sys_var[CS_PRECISION].text, (LONG)sys_precision);
break;
case CS_ROOTDELAY:
ctl_putfp(sys_var[CS_ROOTDELAY].text, sys_rootdelay);
@@ -1220,23 +1241,23 @@ ctl_putsys(varid)
sys_rootdispersion);
break;
case CS_REFID:
- if (sys_stratum > 1)
- ctl_putadr(sys_var[CS_REFID].text, sys_refid);
- else
+ if (sys_stratum <= 1)
ctl_putid(sys_var[CS_REFID].text, (char *)&sys_refid);
+ else
+ ctl_putadr(sys_var[CS_REFID].text, sys_refid);
break;
case CS_REFTIME:
ctl_putts(sys_var[CS_REFTIME].text, &sys_reftime);
break;
case CS_POLL:
- ctl_putuint(sys_var[CS_POLL].text, sys_poll);
+ ctl_putuint(sys_var[CS_POLL].text, (U_LONG)sys_poll);
break;
case CS_PEERID:
if (sys_peer == NULL)
- ctl_putuint(sys_var[CS_PEERID].text, 0);
+ ctl_putuint(sys_var[CS_PEERID].text, (U_LONG)0);
else
ctl_putuint(sys_var[CS_PEERID].text,
- sys_peer->associd);
+ (U_LONG)sys_peer->associd);
break;
case CS_OFFSET:
ctl_putlfp(sys_var[CS_OFFSET].text, &last_offset);
@@ -1245,17 +1266,17 @@ ctl_putsys(varid)
ctl_putfp(sys_var[CS_DRIFT].text, drift_comp);
break;
case CS_COMPLIANCE:
- ctl_putufp(sys_var[CS_COMPLIANCE].text, sys_maxd);
+ ctl_putuint(sys_var[CS_COMPLIANCE].text, (U_LONG)time_constant);
break;
case CS_CLOCK:
get_systime(&tmp);
ctl_putts(sys_var[CS_CLOCK].text, &tmp);
break;
case CS_LEAPIND:
- ctl_putuint(sys_var[CS_LEAPIND].text, leap_indicator);
+ ctl_putuint(sys_var[CS_LEAPIND].text, (U_LONG)leap_indicator);
break;
case CS_LEAPWARNING:
- ctl_putuint(sys_var[CS_LEAPWARNING].text, leap_warning);
+ ctl_putuint(sys_var[CS_LEAPWARNING].text, (U_LONG)leap_warning);
break;
case CS_PROCESSOR:
#ifndef HAVE_UNAME
@@ -1276,7 +1297,7 @@ ctl_putsys(varid)
#endif /* HAVE_UNAME */
break;
case CS_KEYID:
- ctl_putuint(sys_var[CS_KEYID].text, 0);
+ ctl_putuint(sys_var[CS_KEYID].text, (U_LONG)0);
break;
case CS_REFSKEW:
ctl_putlfp(sys_var[CS_REFSKEW].text, &sys_refskew);
@@ -1357,15 +1378,15 @@ ctl_putpeer(varid, peer)
switch (varid) {
case CP_CONFIG:
ctl_putuint(peer_var[CP_CONFIG].text,
- ((peer->flags & FLAG_CONFIG) != 0));
+ (U_LONG)((peer->flags & FLAG_CONFIG) != 0));
break;
case CP_AUTHENABLE:
ctl_putuint(peer_var[CP_AUTHENABLE].text,
- ((peer->flags & FLAG_AUTHENABLE) != 0));
+ (U_LONG)((peer->flags & FLAG_AUTHENABLE) != 0));
break;
case CP_AUTHENTIC:
ctl_putuint(peer_var[CP_AUTHENTIC].text,
- ((peer->flags & FLAG_AUTHENTIC) != 0));
+ (U_LONG)((peer->flags & FLAG_AUTHENTIC) != 0));
break;
case CP_SRCADR:
ctl_putadr(peer_var[CP_SRCADR].text,
@@ -1373,40 +1394,33 @@ ctl_putpeer(varid, peer)
break;
case CP_SRCPORT:
ctl_putuint(peer_var[CP_SRCPORT].text,
- ntohs(peer->srcadr.sin_port));
+ (U_LONG)ntohs(peer->srcadr.sin_port));
break;
case CP_DSTADR:
ctl_putadr(peer_var[CP_DSTADR].text,
- peer->processed ?
- peer->cast_flags & MDF_BCAST ?
- peer->dstadr->bcast.sin_addr.s_addr:
- peer->cast_flags ?
- peer->dstadr->sin.sin_addr.s_addr ?
- peer->dstadr->sin.sin_addr.s_addr:
- peer->dstadr->bcast.sin_addr.s_addr:
- 8 : 12);
+ peer->dstadr->sin.sin_addr.s_addr);
break;
case CP_DSTPORT:
ctl_putuint(peer_var[CP_DSTPORT].text,
- ntohs(peer->dstadr->sin.sin_port));
+ (U_LONG)ntohs(peer->dstadr->sin.sin_port));
break;
case CP_LEAP:
- ctl_putuint(peer_var[CP_LEAP].text, peer->leap);
+ ctl_putuint(peer_var[CP_LEAP].text, (U_LONG)peer->leap);
break;
case CP_HMODE:
- ctl_putuint(peer_var[CP_HMODE].text, peer->hmode);
+ ctl_putuint(peer_var[CP_HMODE].text, (U_LONG)peer->hmode);
break;
case CP_STRATUM:
- ctl_putuint(peer_var[CP_STRATUM].text, peer->stratum);
+ ctl_putuint(peer_var[CP_STRATUM].text, (U_LONG)peer->stratum);
break;
case CP_PPOLL:
- ctl_putuint(peer_var[CP_PPOLL].text, peer->ppoll);
+ ctl_putuint(peer_var[CP_PPOLL].text, (U_LONG)peer->ppoll);
break;
case CP_HPOLL:
- ctl_putuint(peer_var[CP_HPOLL].text, peer->hpoll);
+ ctl_putuint(peer_var[CP_HPOLL].text, (U_LONG)peer->hpoll);
break;
case CP_PRECISION:
- ctl_putint(peer_var[CP_PRECISION].text, peer->precision);
+ ctl_putint(peer_var[CP_PRECISION].text, (LONG)peer->precision);
break;
case CP_ROOTDELAY:
ctl_putfp(peer_var[CP_ROOTDELAY].text, peer->rootdelay);
@@ -1417,12 +1431,7 @@ ctl_putpeer(varid, peer)
break;
case CP_REFID:
if (peer->stratum > 1)
- if (peer->flags & FLAG_REFCLOCK)
- ctl_putadr(peer_var[CP_REFID].text,
- peer->srcadr.sin_addr.s_addr);
- else
- ctl_putadr(peer_var[CP_REFID].text,
- peer->refid);
+ ctl_putadr(peer_var[CP_REFID].text, peer->refid);
else
ctl_putid(peer_var[CP_REFID].text,
(char *)&peer->refid);
@@ -1440,13 +1449,13 @@ ctl_putpeer(varid, peer)
ctl_putts(peer_var[CP_XMT].text, &peer->xmt);
break;
case CP_REACH:
- ctl_puthex(peer_var[CP_REACH].text, peer->reach);
+ ctl_puthex(peer_var[CP_REACH].text, (U_LONG)peer->reach);
break;
case CP_FLASH:
- ctl_puthex(peer_var[CP_FLASH].text, peer->flash);
+ ctl_puthex(peer_var[CP_FLASH].text, (U_LONG)peer->flash);
break;
case CP_VALID:
- ctl_putuint(peer_var[CP_VALID].text, peer->valid);
+ ctl_putuint(peer_var[CP_VALID].text, (U_LONG)peer->valid);
break;
case CP_TIMER:
ctl_putuint(peer_var[CP_TIMER].text,
@@ -1477,7 +1486,7 @@ ctl_putpeer(varid, peer)
(s_fp *)peer->filter_error, (int)peer->filter_nextpt);
break;
case CP_PMODE:
- ctl_putuint(peer_var[CP_PMODE].text, peer->pmode);
+ ctl_putuint(peer_var[CP_PMODE].text, (U_LONG)peer->pmode);
break;
case CP_RECEIVED:
ctl_putuint(peer_var[CP_RECEIVED].text, peer->received);
@@ -1543,7 +1552,8 @@ ctl_putclock(varid, clock, mustput)
case CC_TYPE:
if (mustput || clock->clockdesc == NULL
|| *(clock->clockdesc) == '\0') {
- ctl_putuint(clock_var[CC_TYPE].text, clock->type);
+ ctl_putuint(clock_var[CC_TYPE].text,
+ (U_LONG)clock->type);
}
break;
case CC_TIMECODE:
@@ -1551,7 +1561,7 @@ ctl_putclock(varid, clock, mustput)
(int)clock->lencode);
break;
case CC_POLL:
- ctl_putuint(clock_var[CC_POLL].text, clock->polls);
+ ctl_putuint(clock_var[CC_POLL].text, (U_LONG)clock->polls);
break;
case CC_NOREPLY:
ctl_putuint(clock_var[CC_NOREPLY].text, clock->noresponse);
@@ -1579,17 +1589,14 @@ ctl_putclock(varid, clock, mustput)
break;
case CC_FUDGEVAL2:
if (mustput || (clock->haveflags & CLK_HAVEVAL2))
- if (clock->fudgeval1 > 1)
- ctl_putadr(clock_var[CC_FUDGEVAL2].text,
- clock->fudgeval2);
- else
- ctl_putid(clock_var[CC_FUDGEVAL2].text,
- (char *)&clock->fudgeval2);
+ ctl_putint(clock_var[CC_FUDGEVAL2].text,
+ clock->fudgeval2);
break;
case CC_FLAGS:
if (mustput || (clock->haveflags &
(CLK_HAVEFLAG1|CLK_HAVEFLAG2|CLK_HAVEFLAG3|CLK_HAVEFLAG4)))
- ctl_putuint(clock_var[CC_FLAGS].text, clock->flags);
+ ctl_putuint(clock_var[CC_FLAGS].text,
+ (U_LONG)clock->flags);
break;
case CC_DEVICE:
if (clock->clockdesc == NULL || *(clock->clockdesc) == '\0') {
@@ -1959,8 +1966,8 @@ write_variables(rbufp, restrict)
register struct ctl_var *v;
register int ext_var;
char *valuep;
- long val;
- int leapind, leapwarn;
+ LONG val;
+ u_char leapind, leapwarn;
/*
* If he's trying to write into a peer tell him no way
@@ -1978,8 +1985,8 @@ write_variables(rbufp, restrict)
/*
* Set flags to not-in-sync so we can tell when we get something.
*/
- leapind = ~0;
- leapwarn = ~0;
+ leapind = (u_char)~0;
+ leapwarn = (u_char)~0;
/*
* Look through the variables. Dump out at the first sign of trouble.
@@ -2030,13 +2037,13 @@ write_variables(rbufp, restrict)
switch(v->code) {
case CS_LEAP:
case CS_LEAPIND:
- leapind = val;
+ leapind = (u_char)val;
break;
case CS_LEAPWARNING:
- leapwarn = val;
+ leapwarn = (u_char)val;
break;
default:
- ctl_error(CERR_UNSPEC); /* our fault, really */
+ ctl_error(CERR_UNSPEC); /* our fault, really */
return;
}
}
@@ -2045,7 +2052,7 @@ write_variables(rbufp, restrict)
/*
* If we got anything, do it.
*/
- if (leapind != ~0 || leapwarn != ~0) {
+ if (leapind != (u_char)~0 || leapwarn != (u_char)~0) {
if (!leap_setleap((int)leapind, (int)leapwarn)) {
ctl_error(CERR_PERMISSION);
return;
@@ -2429,32 +2436,18 @@ report_event(err, peer)
if (!(err & PEER_EVENT)) {
if (ctl_sys_num_events < CTL_SYS_MAXEVENTS)
ctl_sys_num_events++;
- if (ctl_sys_last_event != (u_char)err) {
- syslog(LOG_INFO, "system event %x status %x",
- err, ctlsysstatus());
-#ifdef DEBUG
- if (debug)
- printf("report_event: system event %x status %x\n",
- err, ctlsysstatus());
-#endif
- ctl_sys_last_event = (u_char)err;
- }
+ if (ctl_sys_last_event != (u_char)err)
+ syslog(LOG_INFO, "system event %x status %x",
+ err, ctlsysstatus());
+ ctl_sys_last_event = (u_char)err;
} else if (peer != 0) {
peer->last_event = (u_char)(err & ~PEER_EVENT);
if (peer->num_events < CTL_PEER_MAXEVENTS)
- peer->num_events++;
+ peer->num_events++;
syslog(LOG_INFO, "peer %s event %x status %x",
ntoa(&peer->srcadr), err, ctlpeerstatus(peer));
-#ifdef DEBUG
- if (debug)
- printf("peer %s event %x status %x\n",
- ntoa(&peer->srcadr), err, ctlpeerstatus(peer));
-#endif
} else {
syslog(LOG_ERR, "report_event: err %x, no peer", err);
-#ifdef DEBUG
- printf("report_event: err %x, no peer\n", err);
-#endif
return;
}
@@ -2496,8 +2489,10 @@ report_event(err, peer)
clock.kv_list = (struct ctl_var *)0;
refclock_control(&peer->srcadr,
- (struct refclockstat *)0, &clock);
- ctl_puthex("refclockstatus", ctlclkstatus(&clock));
+ (struct refclockstat *)0,
+ &clock);
+ ctl_puthex("refclockstatus",
+ (U_LONG)ctlclkstatus(&clock));
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
@@ -2533,7 +2528,7 @@ report_event(err, peer)
&clock);
ctl_puthex("refclockstatus",
- ctlclkstatus(&clock));
+ (U_LONG)ctlclkstatus(&clock));
for (i = 1; i <= CC_MAXCODE; i++)
ctl_putclock(i, &clock, 0);
@@ -2577,11 +2572,11 @@ ctl_clr_stats()
numasyncmsgs = 0;
}
-static u_long
+static unsigned long
count_var(k)
struct ctl_var *k;
{
- register u_long c;
+ register unsigned long c;
c = 0;
while (k && !(k++->flags & EOV))
@@ -2593,10 +2588,10 @@ count_var(k)
char *
add_var(kv, size, def)
struct ctl_var **kv;
- u_long size;
+ unsigned long size;
int def;
{
- register u_long c;
+ register unsigned long c;
register struct ctl_var *k;
c = count_var(*kv);
@@ -2622,7 +2617,7 @@ void
set_var(kv, data, size, def)
struct ctl_var **kv;
char *data;
- u_long size;
+ unsigned long size;
int def;
{
register struct ctl_var *k;
@@ -2670,7 +2665,7 @@ set_var(kv, data, size, def)
void
set_sys_var(data, size, def)
char *data;
- u_long size;
+ unsigned long size;
int def;
{
set_var(&ext_sys_var, data, size, def);
diff --git a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
index 168ef32..13cbd61 100644
--- a/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
+++ b/usr.sbin/xntpd/xntpd/ntp_loopfilter.c
@@ -1,6 +1,7 @@
/*
* ntp_loopfilter.c - implements the NTP loop filter algorithm
*/
+
#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>
@@ -9,12 +10,45 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
+
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+#include <sys/stat.h>
+#include "ntp_refclock.h"
+#endif /* PPS || PPSCLK || PPSPPS */
+
+#if defined(PPSCLK) || defined(PPSPPS)
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#ifdef HAVE_TERMIOS
+#include <termios.h>
+#endif
+#if defined(STREAM)
+#include <stropts.h>
+#if defined(PPSCLK)
+#include <sys/clkdefs.h>
+#endif /* PPSCLK */
+#endif /* STREAM */
+
+#endif /* PPSCLK || PPSPPS */
+
+#if defined(PPSPPS)
+#include <sys/ppsclock.h>
+#endif /* PPSPPS */
+
#include "ntp_stdlib.h"
#ifdef KERNEL_PLL
-#include "sys/timex.h"
+#include <sys/timex.h>
+#ifndef NTP_SYSCALLS_LIBC
#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
+#endif
#endif /* KERNEL_PLL */
/*
@@ -27,83 +61,122 @@
* seconds. When adjustments are capped inside this range (see
* CLOCK_MAX_{I,F}) both the clock_adjust and the compliance
* registers should be fine. (When the compliance is above 16, it
- * will at most accumulate 2 ** CLOCK_MULT times the maximum offset,
+ * will at most accumulate 2**CLOCK_MULT times the maximum offset,
* which means it fits in a s_fp.)
*
* The skew compensation is a special case. In version 2, it was
- * kept in ms / 4s (i.e., CLOCK_FREQ was 10). In version 3 (Section 5)
- * it seems to be 2 ** -16ms / 4s in a s_fp for a maximum of +-125ppm
+ * kept in ms/4s (i.e., CLOCK_FREQ was 10). In version 3 (Section 5)
+ * it seems to be 2**-16ms/4s in a s_fp for a maximum of +-125ppm
* (stated maximum 100ppm). Since this seems about to change to a
- * larger range, it will be kept in units of 2 ** -20 (CLOCK_DSCALE)
+ * larger range, it will be kept in units of 2**-20 (CLOCK_DSCALE)
* in an s_fp (mainly because that's nearly the same as parts per
* million). Note that this is ``seconds per second'', whereas a
* clock adjustment is a 32-bit fraction of a second to be applied
- * every 2 ** CLOCK_ADJ seconds; to find it, shift the drift right by
- * (CLOCK_DSCALE - 16 - CLOCK_ADJ). When updating the drift, on the
- * other hand, the CLOCK_FREQ factor from the spec assumes the value to
- * be in ``seconds per 4 seconds''; to get our units, CLOCK_ADJ must be
+ * every 2**CLOCK_ADJ seconds; to find it, shift the drift right by
+ * (CLOCK_DSCALE-16-CLOCK_ADJ). When updating the drift, on the other
+ * hand, the CLOCK_FREQ factor from the spec assumes the value to be
+ * in ``seconds per 4 seconds''; to get our units, CLOCK_ADJ must be
* added to the shift.
- *
- * Kernel PLL/PPS state machine
- *
- * The following state machine is used when the kernel PLL modifications
- * described in the README.kernel file are present. The initial
- * configuration routine loop_config() sets up the initial frequency
- * estimate and tests if the kernel modifications are present. If so and
- * the PLL mode bit 1 (STA_PLL) of the mode word in the drift file
- * (ntp.drift) is set, pll_control is set true and the kernel pll is
- * enabled. If the kernel modifications are present and the PLL mode bit
- * 2 (STA_PPSFREQ) is set, the kernel PPS frequency discipline is
- * enabled.
- *
- * Each update to a prefer peer sets pps_update true if it survives the
- * intersection algorithm and its time is within range. The PPS time
- * discipline is enabled (STA_PPSTIME bit set in the status word) when
- * pps_update is true and the PPS frequency discipline is enabled. If
- * the PPS time discipline is enabled and the kernel reports a PPS
- * signal is present, the pps_control variable is set to the current
- * time. If the current time is later than pps_control by PPS_MAXAGE
- * (120 s), this variable is set to zero.
- *
- * The pll_enable switch can be set both at configuration time and at
- * run time using xntpdc. If true, the kernel modifications are active
- * as described above; if false, the kernel is bypassed entirely (except
- * for the PPS frequency update, if enabled) and the daemon PLL used
- * instead.
*/
+
+/*
+ * Macro to compute log2(). We don't want to to this very often, but
+ * needs what must.
+ */
+#define LOG2(r, t) \
+ do { \
+ LONG x = t; \
+ r = 0; \
+ while(x >> 1) \
+ r++; \
+ }
+
#define RSH_DRIFT_TO_FRAC (CLOCK_DSCALE - 16)
#define RSH_DRIFT_TO_ADJ (RSH_DRIFT_TO_FRAC - CLOCK_ADJ)
#define RSH_FRAC_TO_FREQ (CLOCK_FREQ + CLOCK_ADJ - RSH_DRIFT_TO_FRAC)
-#define PPS_MAXAGE 120 /* kernel pps signal timeout (s) */
+#define PPS_MAXAGE 120 /* pps signal timeout (s) */
+#define PPS_MAXUPDATE 600 /* pps update timeout (s) */
/*
* Program variables
*/
- l_fp last_offset; /* last clock offset */
- u_long last_time; /* time of last clock update (s) */
- u_fp clock_stability; /* clock stability (ppm) */
- s_fp clock_frequency; /* clock frequency error (ppm) */
- s_fp drift_comp; /* pll frequency (ppm) */
-static long clock_adjust; /* clock adjust (fraction only) */
-static s_fp max_comp; /* max frequency offset (ppm) */
- int tc_counter; /* poll-adjust counter */
- int pll_status; /* status bits for kernel pll */
+ l_fp last_offset; /* last adjustment done */
+static LONG clock_adjust; /* clock adjust (fraction only) */
+
+ s_fp drift_comp; /* drift compensation register */
+static s_fp max_comp; /* drift limit imposed by max host clock slew */
+
+ int time_constant; /* log2 of time constant (0 .. 4) */
+static U_LONG tcadj_time; /* last time-constant adjust time */
+
+ U_LONG watchdog_timer; /* watchdog timer, in seconds */
+static int first_adjustment; /* 1 if waiting for first adjustment */
+static int tc_counter; /* time-constant hold counter */
+
+static l_fp pps_offset; /* filtered pps offset */
+static u_fp pps_dispersion; /* pps dispersion */
+static U_LONG pps_time; /* last pps sample time */
+
+ int pps_control; /* true if working pps signal */
int pll_control; /* true if working kernel pll */
- int pll_enable; /* true if pll enabled */
- u_long pps_control; /* last pps sample time */
- int pps_update; /* pps update valid */
+static l_fp pps_delay; /* pps tuning offset */
+ U_LONG pps_update; /* last pps update time */
int fdpps = -1; /* pps file descriptor */
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+/*
+ * This module has support for a 1-pps signal to fine-tune the local
+ * clock. The signal is optional; when present and operating within
+ * given tolerances in frequency and jitter, it is used to discipline
+ * the local clock. In order for this to work, the local clock must be
+ * set to within +-500 ms by another means, such as a radio clock or
+ * NTP itself. The 1-pps signal is connected via a serial port and
+ * gadget box consisting of a one-shot and EIA level-converter. When
+ * operated at 38.4 kbps with a SPARCstation IPC, this arrangement has a
+ * worst-case jitter less than 26 us. The pps delay configuration
+ * declaration can be used to compensate for miscellaneous uart and
+ * os delays. Allow about 247 us for uart delays at 38400 bps and
+ * -1 ms for SunOS streams nonsense.
+ */
+
+/*
+ * A really messy way to map an integer baud rate to the system baud rate.
+ * There should be a better way.
+ */
+#define SYS_BAUD(i) \
+ ( i == 38400 ? B38400 : \
+ ( i == 19200 ? B19200 : \
+ ( i == 9600 ? B9600 : \
+ ( i == 4800 ? B4800 : \
+ ( i == 2400 ? B2400 : \
+ ( i == 1200 ? B1200 : \
+ ( i == 600 ? B600 : \
+ ( i == 300 ? B300 : 0 ))))))))
+
+#define PPS_BAUD B38400 /* default serial port speed */
+timecode */
+#define PPS_DEV "/dev/pps" /* pps port */
+#define PPS_FAC 3 /* pps shift (log2 trimmed samples) */
+#define PPS_TRIM 6 /* samples trimmed from median filter */
+#define NPPS ((1 << PPS_FAC) + 2 * PPS_TRIM) /* pps filter size */
+#define PPS_XCPT "\377" /* intercept character */
+
+#if defined(PPSCLK)
+static struct refclockio io; /* given to the I/O handler */
+static int pps_baud; /* baud rate of PPS line */
+#endif /* PPSCLK */
+static U_LONG nsamples; /* number of pps samples collected */
+static LONG samples[NPPS]; /* median filter for pps samples */
+
+#endif /* PPS || PPSCLK || PPSPPS */
+
/*
* Imported from the ntp_proto module
*/
-extern s_fp sys_rootdelay; /* root delay */
-extern u_fp sys_rootdispersion; /* root dispersion */
-extern struct peer *sys_peer; /* system peer pointer */
-extern u_char sys_poll; /* log2 of system poll interval */
-extern u_char sys_leap; /* system leap bits */
-extern l_fp sys_refskew; /* accumulated skew since last update */
-extern u_fp sys_maxd; /* max dispersion of survivor list */
+extern u_char sys_stratum;
+extern s_fp sys_rootdelay;
+extern u_fp sys_rootdispersion;
+extern s_char sys_precision;
/*
* Imported from ntp_io.c
@@ -118,20 +191,41 @@ extern int debug; /* global debug flag */
/*
* Imported from timer module
*/
-extern u_long current_time; /* like it says, in seconds */
+extern U_LONG current_time; /* like it says, in seconds */
+
+/*
+ * sys_poll and sys_refskew are set here
+ */
+extern u_char sys_poll; /* log2 of system poll interval */
+extern u_char sys_leap; /* system leap bits */
+extern l_fp sys_refskew; /* accumulated skew since last update */
+extern u_fp sys_maxd; /* max dispersion of survivor list */
/*
* Imported from leap module
*/
extern u_char leapbits; /* sanitized leap bits */
+/*
+ * Function prototypes
+ */
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+int pps_sample P((l_fp *));
+#if defined(PPSCLK)
+static void pps_receive P((struct recvbuf *));
+#endif /* PPSCLK */
+#endif /* PPS || PPSCLK || PPSPPS */
+
#if defined(KERNEL_PLL)
#define MOD_BITS (MOD_OFFSET | MOD_MAXERROR | MOD_ESTERROR | \
MOD_STATUS | MOD_TIMECONST)
extern int sigvec P((int, struct sigvec *, struct sigvec *));
+#ifndef NTP_SYSCALLS_LIBC
extern int syscall P((int, void *, ...));
+#endif /* no NTP syscalls in libc */
void pll_trap P((void));
+static int pll_status; /* status bits for kernel pll */
static struct sigvec sigsys; /* current sigvec status */
static struct sigvec newsigsys; /* new sigvec status */
#endif /* KERNEL_PLL */
@@ -142,164 +236,299 @@ static struct sigvec newsigsys; /* new sigvec status */
void
init_loopfilter()
{
- extern u_long tsf_maxslew;
- u_long tsf_limit;
+ extern U_LONG tsf_maxslew;
+ U_LONG tsf_limit;
+#if defined(PPSCLK)
+ int fd232;
+#endif /* PPSCLK */
+ clock_adjust = 0;
+ drift_comp = 0;
+ time_constant = 0;
+ tcadj_time = 0;
+ watchdog_timer = 0;
+ tc_counter = 0;
+ last_offset.l_i = 0;
+ last_offset.l_f = 0;
+ first_adjustment = 1;
- /*
- * Limit for drift_comp, minimum of two values. The first is to
- * avoid signed overflow, the second to keep within 75% of the
- * maximum adjustment possible in adj_systime().
- */
+/*
+ * Limit for drift_comp, minimum of two values. The first is to avoid
+ * signed overflow, the second to keep within 75% of the maximum
+ * adjustment possible in adj_systime().
+ */
max_comp = 0x7fff0000;
tsf_limit = ((tsf_maxslew >> 1) + (tsf_maxslew >> 2));
if ((max_comp >> RSH_DRIFT_TO_ADJ) > tsf_limit)
max_comp = tsf_limit << RSH_DRIFT_TO_ADJ;
+ pps_control = 0;
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+#if defined(PPSCLK)
+ pps_baud = PPS_BAUD;
+#endif /* PPSCLK */
+ pps_delay.l_i = 0;
+ pps_delay.l_f = 0;
+ pps_time = pps_update = 0;
+ nsamples = 0;
+#if defined(PPSCLK)
+
/*
- * Reset clockworks
+ * Open pps serial port. We don't care if the serial port comes
+ * up; if not, we just use the timecode. Therefore, if anything
+ * goes wrong, just reclaim the resources and continue.
*/
- drift_comp = 0;
- clock_adjust = 0;
- tc_counter = 0;
- sys_poll = NTP_MINPOLL;
+ fd232 = open(PPS_DEV, O_RDONLY);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "loopfilter: open of %s: %m", PPS_DEV);
+ return;
+ }
- L_CLR(&last_offset);
- last_time = 0;
- clock_frequency = 0;
- clock_stability = 0;
- pps_update = pps_control = 0;
+#if !defined(HPUXGADGET) /* dedicated to Ken Stone */
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ */
+ PPSCLK SUPPORT NOT AVAILABLE IN TERMIO INTERFACE
+#endif /* HAVE_SYSV_TTYS */
+#if defined(HAVE_TERMIOS)
+ /*
+ * POSIX serial line parameters (termios interface)
+ *
+ * The PPSCLK option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the tty_clk streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: tcgetattr(%s): %m", PPS_DEV);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = PPS_BAUD|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: tcsetattr(%s): %m", PPS_DEV);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: tcflush(%s): %m", PPS_DEV);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(STREAM)
+ while (ioctl(fd232, I_POP, 0 ) >= 0) ;
+ if (ioctl(fd232, I_PUSH, "clk") < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: ioctl(%s, I_PUSH, clk): %m", PPS_DEV);
+ goto screwed;
+ }
+ if (ioctl(fd232, CLK_SETSTR, PPS_XCPT) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: ioctl(%s, CLK_SETSTR, PPS_XCPT): %m", PPS_DEV);
+ goto screwed;
+ }
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The PPSCLK option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+ int ldisc = CLKLDISC;
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: ioctl(%s, TIOCGETP): %m", PPS_DEV);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = PPS_BAUD;
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: ioctl(%s, TIOCSETP): %m", PPS_DEV);
+ goto screwed;
+ }
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "loopfilter: ioctl(%s, TIOCSETD): %m", PPS_DEV);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_BSD_TTYS */
+#endif /* HPUXGADGET */
+ fdpps = fd232;
+
+ /*
+ * Insert in device list.
+ */
+ io.clock_recv = pps_receive;
+ io.srcclock = (caddr_t)NULL;
+ io.datalen = 0;
+ io.fd = fdpps;
+#if defined(HPUXGADGET)
+ if (!io_addclock_simple(&io))
+#else
+ if (!io_addclock(&io))
+#endif /* HPUXGADGET */
+ goto screwed;
+ return;
+
+ /*
+ * Something broke. Reclaim resources.
+ */
+screwed:
+ (void)close(fdpps);
+ return;
+#endif /* PPSCLK */
+#endif /* PPS || PPSCLK || PPSPPS */
}
/*
* local_clock - the NTP logical clock loop filter. Returns 1 if the
- * clock was stepped, 0 if it was slewed and -1 if it is hopeless.
+ * clock was stepped, 0 if it was slewed and -1 if it is
+ * hopeless.
*/
int
local_clock(fp_offset, peer)
l_fp *fp_offset; /* best offset estimate */
struct peer *peer; /* from peer - for messages */
{
- long offset;
- long tmp;
- int return_code;
- l_fp ftmp;
- s_fp stmp;
- u_fp smax;
- long allan;
- long interval;
+ register LONG offset;
+ register U_LONG tmp_ui;
+ register U_LONG tmp_uf;
+ register LONG tmp;
+ int isneg;
#if defined(KERNEL_PLL)
struct timex ntv;
#endif /* KERNEL_PLL */
- /*
- * Initialize estimated measurement error and Allan variance
- * intercept point. The measurement error is assumed the sum of
- * the peer dispersion plus select dispersion, which seems
- * reasonable. The Allan variance intercept point is assumed
- * at MAXSEC for reference clocks and twice that for peer
- * clocks, which seems cowardly.
- */
- if (peer->refclktype)
- allan = CLOCK_MAXSEC;
- else
- allan = CLOCK_MAXSEC << 1;
-
- if (!last_time)
- last_time = current_time;
- interval = (long)(current_time - last_time);
- clock_adjust = 0;
- offset = fp_offset->l_f;
- smax = peer->dispersion + peer->selectdisp;
- return_code = 0;
-
#ifdef DEBUG
if (debug > 1)
- printf(
- "local_clock: offset %s peer %s watch %ld)\n",
- lfptoa(fp_offset, 6), ntoa(&peer->srcadr),
- interval);
+ printf("local_clock(%s, %s)\n", lfptoa(fp_offset, 6),
+ ntoa(&peer->srcadr));
#endif
/*
+ * Take the absolute value of the offset
+ */
+ tmp_ui = fp_offset->l_ui;
+ tmp_uf = fp_offset->l_uf;
+ if (M_ISNEG(tmp_ui, tmp_uf)) {
+ M_NEG(tmp_ui, tmp_uf);
+ isneg = 1;
+ } else
+ isneg = 0;
+
+ /*
* If the clock is way off, don't tempt fate by correcting it.
*/
- ftmp = *fp_offset;
- if (L_ISNEG(&ftmp))
- L_NEG(&ftmp);
- if (ftmp.l_ui >= CLOCK_WAYTOOBIG) {
+ if (tmp_ui >= CLOCK_WAYTOOBIG) {
syslog(LOG_ERR,
- "time error %s is way too large (set clock manually)",
- lfptoa(fp_offset, 6));
+ "Clock appears to be %u seconds %s, something may be wrong",
+ tmp_ui, isneg>0?"fast":"slow");
#ifndef BIGTIMESTEP
return (-1);
#endif /* BIGTIMESTEP */
+ }
/*
- * If the magnitude of the offset is greater than CLOCK.MAX
- * (128 ms), reset the time and frequency. We are quite
- * aggresive here, since the intrinsic clock oscillator
- * frequency error can be quite large, sometimes over +-300 ppm.
- * With something this large and a noisy peer, the casual time
- * updates wander right through the acceptable range, causing
- * this section to trigger.
+ * Save this offset for later perusal
*/
- } else if (ftmp.l_ui > CLOCK_MAX_I || (ftmp.l_ui == CLOCK_MAX_I
- && ftmp.l_uf >= CLOCK_MAX_F)) {
- tc_counter = 0;
- sys_poll = peer->minpoll;
-
- /*
- * Either we are not in synchronization, or we have gone
- * CLOCK_MINSTEP (900 s) since the last acceptable
- * update. We step the clock and leave the frequency
- * alone. Since the clock filter has been reset, the
- * dispersions will be high upon recovery and the quick-
- * march code below will trigger to keep the clock in
- * bounds.
- */
- if (sys_leap == LEAP_NOTINSYNC || interval >
- CLOCK_MINSTEP) {
- step_systime(fp_offset);
- syslog(LOG_NOTICE,
+ last_offset = *fp_offset;
- "time reset (%s) %s s",
+ /*
+ * If the magnitude of the offset is greater than CLOCK.MAX,
+ * step the time and reset the registers.
+ */
+ if (tmp_ui > CLOCK_MAX_I || (tmp_ui == CLOCK_MAX_I
+ && (U_LONG)tmp_uf >= (U_LONG)CLOCK_MAX_F)) {
+ if (watchdog_timer < CLOCK_MINSTEP) {
+ /* Mustn't step yet, pretend we adjusted. */
+ syslog(LOG_INFO,
+ "clock correction %s too large (ignored)\n",
+ lfptoa(fp_offset, 6));
+ return (0);
+ }
+ syslog(LOG_NOTICE, "clock reset (%s) %s\n",
#ifdef SLEWALWAYS
- "slew",
+ "slew",
#else
- "step",
+ "step",
#endif
- lfptoa(fp_offset, 6));
- return_code = 1;
-
- /*
- * The local clock is out of range, but we haven't
- * allowed enough time for the peer (usually a radio
- * clock) to recover after a leap second. Pretend we wuz
- * never here.
- */
- } else
- return (return_code);
+ lfptoa(fp_offset, 6));
+ step_systime(fp_offset);
+ clock_adjust = 0;
+ watchdog_timer = 0;
+ first_adjustment = 1;
+ pps_update = 0;
+ return (1);
+ }
/*
- * This code segment works when the clock-adjustment code is
+ * Here we've got an offset small enough to slew. Note that
+ * since the offset is small we don't have to carry the damned
+ * high order longword in our calculations.
+ *
+ * The time constant and sample interval are approximated with
+ * shifts, as in Section 5 of the v3 spec. The spec procedure
+ * looks strange, as an interval of 64 to 127 seconds seems to
+ * cause multiplication with 128 (and so on). This code lowers
+ * the multiplier by one bit.
+ *
+ * The time constant update goes after adjust and skew updates,
+ * as in appendix G.
+ */
+ /*
+ * If pps samples are valid, update offset, root delay and
+ * root dispersion. Also, set the system stratum to 1, even if
+ * the source of approximate time runs at a higher stratum. This
+ * may be a dramatic surprise to high-stratum clients, since all
+ * of a sudden this server looks like a stratum-1 clock.
+ */
+ if (pps_control) {
+ last_offset = pps_offset;
+ sys_maxd = pps_dispersion;
+ sys_stratum = 1;
+ sys_rootdelay = 0;
+ offset = LFPTOFP(&pps_offset);
+ if (offset < 0)
+ offset = -offset;
+ sys_rootdispersion = offset + pps_dispersion;
+ }
+ offset = last_offset.l_f;
+
+ /*
+ * The pll_control is active when the phase-lock code is
* implemented in the kernel, which at present is only in the
- * (modified) SunOS 4.1, Ultrix 4.3 and OSF/1 kernels. In the
+ * (modified) SunOS 4.1.x, Ultrix 4.3 and OSF/1 kernels. In the
* case of the DECstation 5000/240 and Alpha AXP, additional
- * kernel modifications provide a true microsecond clock. We
- * know the scaling of the frequency variable (s_fp) is the same
- * as the kernel variable (1 << SHIFT_USEC = 16).
- */
+ * kernal modifications provide a true microsecond clock. We
+ * know the scaling of the frequency variable (s_fp) is the
+ * same as the kernel variable (1 << SHIFT_USEC = 16).
+ *
+ * For kernels with the PPS discipline, the current offset and
+ * dispersion are set from kernel variables to maintain
+ * beauteous displays, but don't do much of anything.
+ *
+ * In the case of stock kernels the phase-lock loop is
+ * implemented the hard way and the clock_adjust and drift_comp
+ * computed as required.
+ */
+ if (pll_control) {
#if defined(KERNEL_PLL)
- } else if (pll_control && pll_enable) {
- l_fp pps_offset;
- u_fp pps_dispersion;
-
- /*
- * We initialize the structure for the ntp_adjtime()
- * system call. We have to convert everything to
- * microseconds first. Afterwards, remember the
- * frequency offset for the drift file.
- */
memset((char *)&ntv, 0, sizeof ntv);
ntv.modes = MOD_BITS;
if (offset >= 0) {
@@ -308,310 +537,210 @@ local_clock(fp_offset, peer)
TSFTOTVU(-offset, ntv.offset);
ntv.offset = -ntv.offset;
}
- TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2,
- ntv.maxerror);
+ TSFTOTVU(sys_rootdispersion + sys_rootdelay / 2, ntv.maxerror);
TSFTOTVU(sys_rootdispersion, ntv.esterror);
- ntv.status = pll_status & (STA_PLL | STA_PPSFREQ);
- if (pps_update && pll_status & STA_PPSFREQ)
+ ntv.status = pll_status;
+ if (pps_update)
ntv.status |= STA_PPSTIME;
if (sys_leap & LEAP_ADDSECOND &&
- sys_leap & LEAP_DELSECOND)
+ sys_leap & LEAP_DELSECOND)
ntv.status |= STA_UNSYNC;
else if (sys_leap & LEAP_ADDSECOND)
ntv.status |= STA_INS;
else if (sys_leap & LEAP_DELSECOND)
ntv.status |= STA_DEL;
- ntv.constant = min(peer->ppoll, sys_poll) - NTP_MINPOLL;
+ ntv.constant = time_constant;
(void)ntp_adjtime(&ntv);
drift_comp = ntv.freq;
- pll_status = ntv.status;
-
- /*
- * If the kernel pps discipline is working, monitor its
- * performance.
- */
- if (pll_status & STA_PPSTIME && pll_status &
- STA_PPSSIGNAL && ntv.shift) {
- if (ntv.offset >= 0)
+ if (ntv.status & STA_PPSTIME && ntv.status & STA_PPSSIGNAL
+ && ntv.shift) {
+ if (ntv.offset >= 0) {
TVUTOTSF(ntv.offset, offset);
- else {
+ } else {
TVUTOTSF(-ntv.offset, offset);
offset = -offset;
}
- L_CLR(&pps_offset);
- L_ADDF(&pps_offset, offset);
+ pps_offset.l_i = pps_offset.l_f = 0;
+ M_ADDF(pps_offset.l_i, pps_offset.l_f, offset);
TVUTOTSF(ntv.jitter, tmp);
pps_dispersion = (tmp >> 16) & 0xffff;
- if (!pps_control)
- syslog(LOG_INFO,
- "kernel pps sync enabled");
- pps_control = current_time;
+ pps_time = current_time;
record_peer_stats(&loopback_interface->sin,
- ctlsysstatus(), fp_offset, 0,
- pps_dispersion);
- }
+ ctlsysstatus(), &pps_offset, 0, pps_dispersion);
+ } else
+ pps_time = 0;
#endif /* KERNEL_PLL */
-
- /*
- * If the dispersion exceeds 128 ms, we need to quick-march it
- * to nominal zero offset and wait for the next update. This is
- * necessary when the intrinsic frequency error is large and the
- * clock has drifted during the interval the clock filter was
- * stabilizing. Note that, if unsynchronized, the dispersion is
- * always greater than 128 ms, so we don't need a check for
- * that.
- */
- } else if (smax > CLOCK_MAX_FP) {
- clock_adjust = offset;
-
- /*
- * If the dispersion has increased substantially over the
- * previous value, we have a spike which probably should be
- * suppressed. A factor of eight has been found reasonable by
- * simulation.
- */
- } else if (smax > sys_maxd << 3) {
- return (0);
-
- /*
- * If the interval between corrections is less than the Allan
- * variance intercept point, we use a phase-lock loop to compute
- * new values of time and frequency. The bandwidth is controlled
- * by the time constant, which is adjusted in response to the
- * phase error and dispersion. Note the frequency is not changed
- * if the local clock driver is in control.
- */
- } else if (interval < allan) {
- int time_constant = min(peer->ppoll, sys_poll) -
- NTP_MINPOLL;
- int ltmp = interval;
-
- if (offset < 0)
- clock_adjust = -(-offset >> time_constant);
- else
+ } else {
+ if (offset < 0) {
+ clock_adjust = -((-offset) >> time_constant);
+ } else {
clock_adjust = offset >> time_constant;
- if (interval && !(peer->refclktype ==
- REFCLK_LOCALCLOCK)) {
+ }
+
+ /*
+ * Calculate the new frequency error. The factor given
+ * in the spec gives the adjustment per 2**CLOCK_ADJ
+ * seconds, but we want it as a (scaled) pure ratio, so
+ * we include that factor now and remove it later.
+ */
+ if (first_adjustment) {
+ first_adjustment = 0;
+ } else {
tmp = peer->maxpoll;
- while (ltmp < (1 << peer->maxpoll)) {
+ tmp_uf = watchdog_timer;
+ if (tmp_uf == 0)
+ tmp_uf = 1;
+ while (tmp_uf < (1 << peer->maxpoll)) {
tmp--;
- ltmp <<= 1;
+ tmp_uf <<= 1;
}
- tmp = (RSH_FRAC_TO_FREQ - tmp) + time_constant +
- time_constant;
+
+ /*
+ * We apply the frequency scaling at the same
+ * time as the sample interval; this ensures a
+ * safe right-shift. (as long as it keeps below
+ * 31 bits, which current parameters should
+ * ensure.
+ */
+ tmp = (RSH_FRAC_TO_FREQ - tmp) +
+ time_constant + time_constant;
if (offset < 0)
- tmp = -(-offset >> tmp);
+ tmp = -((-offset) >> tmp);
else
tmp = offset >> tmp;
drift_comp += tmp;
+ if (drift_comp > max_comp)
+ drift_comp = max_comp;
+ else if (drift_comp < -max_comp)
+ drift_comp = -max_comp;
}
-
- /*
- * If the interval between corrections is greater than the Allan
- * variance intercept point, we use a hybrid frequency-lock loop
- * to compute new values of phase and frequency. The following
- * code is based on ideas suggested by Judah Levine of NIST and
- * used in his "lockclock" implementation of ACTS. The magic
- * factor of 4 in the left shift is to convert from s_fp to ppm.
- */
- } else {
- clock_adjust = offset;
- stmp = (offset / interval) << 4;
- if (stmp < 0)
- drift_comp -= -stmp >> CLOCK_G;
- else
- drift_comp += stmp >> CLOCK_G;
}
+ watchdog_timer = 0;
/*
- * As a sanity check, we clamp the frequency not to exceed the
- * slew rate of the stock Unix adjtime() system call. Finally,
- * do a little housekeeping.
+ * Determine when to adjust the time constant and poll interval.
*/
- if (drift_comp > max_comp)
- drift_comp = max_comp;
- else if (drift_comp < -max_comp)
- drift_comp = -max_comp;
- if (interval > (1 << (peer->minpoll - 1))) {
-
- /*
- * Determine when to adjust the poll interval. We do
- * this regardless of what source controls the loop,
- * since we might flap back and forth between sources.
- */
- stmp = LFPTOFP(fp_offset);
- if (stmp < 0)
- stmp = -stmp;
- if (stmp > smax) {
- tc_counter -= (int)sys_poll << 1;
- if (tc_counter < -CLOCK_LIMIT) {
- tc_counter = -CLOCK_LIMIT;
- if (sys_poll > peer->minpoll) {
- sys_poll--;
- tc_counter = 0;
- }
- }
+ if (pps_control)
+ time_constant = 0;
+ else if (current_time - tcadj_time >= (1 << sys_poll) && !pps_control) {
+ tcadj_time = current_time;
+ tmp = offset;
+ if (tmp < 0)
+ tmp = -tmp;
+ tmp = tmp >> (16 + CLOCK_WEIGHTTC - time_constant);
+ if (tmp > sys_maxd) {
+ tc_counter = 0;
+ time_constant--;
} else {
- tc_counter += (int)sys_poll;
- if (tc_counter > CLOCK_LIMIT) {
- tc_counter = CLOCK_LIMIT;
- if (sys_poll < peer->maxpoll) {
- sys_poll++;
- tc_counter = 0;
- }
+ tc_counter++;
+ if (tc_counter > CLOCK_HOLDTC) {
+ tc_counter = 0;
+ time_constant++;
}
}
-
- /*
- * Calculate the frequency offset and frequency
- * stability. These are useful for performance
- * monitoring, but do not affect the loop variables. The
- * results are scaled as a s_fp in ppm, because we know
- * more than we should.
- */
- ftmp = *fp_offset;
- L_SUB(&ftmp, &last_offset);
- clock_frequency = (LFPTOFP(&ftmp) / interval) << 20;
- if (clock_frequency < -max_comp)
- clock_frequency = -max_comp;
- else if (clock_frequency > max_comp)
- clock_frequency = max_comp;
- stmp = clock_frequency;
- if (stmp < 0)
- stmp = -stmp;
- stmp -= clock_stability;
- if (stmp < 0)
- clock_stability -= -stmp >> NTP_MAXD;
- else
- clock_stability += stmp >> NTP_MAXD;
+ if (time_constant < (int)(peer->minpoll - NTP_MINPOLL))
+ time_constant = peer->minpoll - NTP_MINPOLL;
+ if (time_constant > (int)(peer->maxpoll - NTP_MINPOLL))
+ time_constant = peer->maxpoll - NTP_MINPOLL;
}
- last_offset = *fp_offset;
- last_time = current_time;
+ sys_poll = (u_char)(NTP_MINPOLL + time_constant);
#ifdef DEBUG
if (debug > 1)
- printf(
- "local_clock: phase %s freq %s err %s allan %ld poll %d\n",
- mfptoa((clock_adjust < 0 ? -1 : 0), clock_adjust,
- 6), fptoa(drift_comp, 3), fptoa(smax, 6), allan,
- sys_poll);
+ printf("adj %s, drft %s, tau %3i\n",
+ mfptoa((clock_adjust<0?-1:0), clock_adjust, 6),
+ fptoa(drift_comp, 6), time_constant);
#endif /* DEBUG */
- (void) record_loop_stats(fp_offset, drift_comp, sys_poll);
+ (void) record_loop_stats(&last_offset, &drift_comp, time_constant);
/*
* Whew. I've had enough.
*/
- return (return_code);
+ return (0);
}
/*
- * adj_host_clock - Called every 1 << CLOCK_ADJ seconds to update host
- * clock
+ * adj_host_clock - Called every 2**CLOCK_ADJ seconds to update host clock
*/
void
adj_host_clock()
{
- register long adjustment;
- l_fp offset;
-
- /*
- * Update the dispersion since the last update. Don't allow
- * frequency measurements over periods longer than NTP_MAXAGE
- * (86400 s = one day).
- */
- if (current_time - last_time > NTP_MAXAGE)
- last_time = 0;
- L_ADDUF(&sys_refskew, NTP_SKEWINC);
+ register LONG adjustment;
+#if defined(PPSPPS)
+ struct ppsclockev ev;
+ l_fp ts;
+#endif /* PPSPPS */
+
+ watchdog_timer += (1 << CLOCK_ADJ);
+ if (watchdog_timer >= NTP_MAXAGE) {
+ first_adjustment = 1; /* don't use next offset for freq */
+ }
+ if (sys_refskew.l_i >= NTP_MAXSKEW)
+ sys_refskew.l_f = 0; /* clamp it */
+ else
+ L_ADDUF(&sys_refskew, NTP_SKEWINC);
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+#if defined(PPSPPS)
/*
- * Declare PPS kernel unsync if the pps signal has been heard
- * during the last few minutes.
+ * Note that nothing ugly happens even if the CIOGETEV ioctl is
+ * not configured. Correct for signal delays (!) for ultimate
+ * finick.
*/
- if (pps_control && current_time - pps_control > PPS_MAXAGE) {
+ if (fdpps != -1 && ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
+ static int last_serial = 0; /* avoid stale events */
+
+ if (last_serial != ev.serial) {
+ TVUTOTSF(ev.tv.tv_usec, ts.l_uf);
+ ts.l_ui = 0; /* seconds don't matter here */
+ L_SUB(&ts, &pps_delay);
+ ts.l_uf = ~ts.l_uf; /* map [0.5..1[ into [-0.5..0[ */
+ ts.l_ui = (ts.l_f < 0) ? ~0 : 0; /* sign extension */
+ (void)pps_sample(&ts);
+ last_serial = ev.serial;
+ }
+ }
+#endif /* PPSPPS */
+#endif /* PPS || PPSCLK || PPSPPS */
+ if (pps_time && current_time - pps_time > PPS_MAXAGE)
+ pps_time = 0;
+ if (pps_update && current_time - pps_update > PPS_MAXUPDATE)
+ pps_update = 0;
+ if (pps_time && pps_update) {
+ if (!pps_control)
+ syslog(LOG_INFO, "PPS synch");
+ pps_control = 1;
+ } else {
if (pps_control)
- syslog(LOG_INFO, "kernel pps sync disabled");
+ syslog(LOG_INFO, "PPS synch lost");
pps_control = 0;
}
/*
- * If the phase-lock loop is not implemented in the kernel, we
- * do it the hard way using incremental adjustments and the
- * adjtime() system call.
+ * Resist the following code if the phase-lock loop has been
+ * implemented in the kernel.
*/
- if (pll_control && pll_enable)
+ if (pll_control)
return;
adjustment = clock_adjust;
if (adjustment < 0)
- adjustment = -(-adjustment >> CLOCK_PHASE);
+ adjustment = -((-adjustment) >> CLOCK_PHASE);
else
adjustment >>= CLOCK_PHASE;
clock_adjust -= adjustment;
if (drift_comp < 0)
- adjustment -= -drift_comp >> RSH_DRIFT_TO_ADJ;
+ adjustment -= ((-drift_comp) >> RSH_DRIFT_TO_ADJ);
else
adjustment += drift_comp >> RSH_DRIFT_TO_ADJ;
- /*
- * Intricate wrinkle. If the local clock driver is in use and
- * selected for synchronization, somebody else may be tinker the
- * adjtime() syscall. In this case we have to avoid calling
- * adjtime(), since that may truncate the other guy's requests.
- * That means the local clock fudge time and frequency
- * adjustments don't work in that case. Caveat empty.
- */
- if (sys_peer) {
- if (sys_peer->refclktype == REFCLK_LOCALCLOCK &&
- sys_peer->flags & FLAG_PREFER)
- return;
+ { l_fp offset;
+ offset.l_i = 0;
+ offset.l_f = adjustment;
+ adj_systime(&offset);
}
- L_CLR(&offset);
- L_ADDF(&offset, adjustment);
- adj_systime(&offset);
-}
-
-
-/*
- * adj_frequency - adjust local clock frequency
- */
-void
-adj_frequency(freq)
- s_fp freq; /* frequency (ppm) */
-{
-#if defined(KERNEL_PLL)
- struct timex ntv;
-#endif /* KERNEL_PLL */
-
- /*
- * This routine adjusts the frequency offset. It is used by the
- * local clock driver to adjust frequency when no external
- * discipline source is available and by the acts driver when
- * the interval between updates is greater than 1 <<
- * NTP_MAXPOLL. Note that the maximum offset is limited by
- * max_comp when the daemon pll is used, but the maximum may be
- * different when the kernel pll is used.
- */
- drift_comp += freq;
- if (drift_comp > max_comp)
- drift_comp = max_comp;
- else if (drift_comp < -max_comp)
- drift_comp = -max_comp;
-#if defined(KERNEL_PLL)
- /*
- * If the phase-lock code is implemented in the kernel, set the
- * kernel frequency as well, but be sure to set drift_comp to
- * the actual frequency.
- */
- if (!(pll_control && pll_enable))
- return;
- memset((char *)&ntv, 0, sizeof ntv);
- ntv.modes = MOD_FREQUENCY;
- ntv.freq = freq + drift_comp;
- (void)ntp_adjtime(&ntv);
- drift_comp = ntv.freq;
-#endif /* KERNEL_PLL */
}
@@ -624,76 +753,106 @@ loop_config(item, lfp_value, int_value)
l_fp *lfp_value;
int int_value;
{
+ s_fp tmp;
#if defined(KERNEL_PLL)
struct timex ntv;
#endif /* KERNEL_PLL */
-#ifdef DEBUG
- if (debug) {
- printf("loop_config %d %s %x\n", item,
- lfptoa(lfp_value, 3), int_value);
- }
-#endif
switch (item) {
-
- case LOOP_DRIFTCOMP:
- drift_comp = LFPTOFP(lfp_value);
- if (drift_comp > max_comp)
- drift_comp = max_comp;
- if (drift_comp < -max_comp)
- drift_comp = -max_comp;
+ case LOOP_DRIFTCOMP:
+ tmp = LFPTOFP(lfp_value);
+ if (tmp >= max_comp || tmp <= -max_comp) {
+ syslog(LOG_ERR,
+ "loop_config: frequency offset %s in ntp.conf file is too large",
+ fptoa(tmp, 5));
+ } else {
+ drift_comp = tmp;
#if defined(KERNEL_PLL)
- /*
- * If the phase-lock code is implemented in the kernel,
- * give the time_constant and saved frequency offset to
- * the kernel. If not, no harm is done. We do this
- * whether or not the use of the kernel mods is
- * requested, in order to clear out the trash from
- * possible prior customers.
- */
- memset((char *)&ntv, 0, sizeof ntv);
- pll_status = int_value & (STA_PLL | STA_PPSFREQ);
- if (pll_status & STA_PLL)
+ /*
+ * If the phase-lock code is implemented in the
+ * kernel, give the time_constant and saved
+ * frequency offset to the kernel. If not, no
+ * harm is done.
+ */
pll_control = 1;
- else
- pll_control = 0;
- ntv.modes = MOD_BITS | MOD_FREQUENCY;
- if (pll_status) {
+ pll_status = STA_PLL | STA_PPSFREQ;
+ ntv.modes = MOD_BITS | MOD_FREQUENCY;
+ ntv.offset = 0;
ntv.freq = drift_comp;
ntv.maxerror = NTP_MAXDISPERSE;
ntv.esterror = NTP_MAXDISPERSE;
ntv.status = pll_status | STA_UNSYNC;
- ntv.constant = sys_poll - NTP_MINPOLL;
- }
- newsigsys.sv_handler = pll_trap;
- newsigsys.sv_mask = 0;
- newsigsys.sv_flags = 0;
- if ((sigvec(SIGSYS, &newsigsys, &sigsys)))
- syslog(LOG_ERR,
- "sigvec() fails to save SIGSYS trap: %m");
- (void)ntp_adjtime(&ntv);
- if ((sigvec(SIGSYS, &sigsys,
- (struct sigvec *)NULL)))
- syslog(LOG_ERR,
- "sigvec() fails to restore SIGSYS trap: %m");
- if (pll_control)
- syslog(LOG_NOTICE,
- "using kernel phase-lock loop %04x",
- ntv.status);
- else
- syslog(LOG_NOTICE,
- "using xntpd phase-lock loop");
+ ntv.constant = time_constant;
+ newsigsys.sv_handler = pll_trap;
+ newsigsys.sv_mask = 0;
+ newsigsys.sv_flags = 0;
+ if ((sigvec(SIGSYS, &newsigsys, &sigsys)))
+ syslog(LOG_ERR,
+ "sigvec() fails to save SIGSYS trap: %m\n");
+ (void)ntp_adjtime(&ntv);
+ if ((sigvec(SIGSYS, &sigsys, (struct sigvec *)NULL)))
+ syslog(LOG_ERR,
+ "sigvec() fails to restore SIGSYS trap: %m\n");
+ if (pll_control)
+ syslog(LOG_NOTICE,
+ "using kernel phase-lock loop %04x",
+ ntv.status);
+ else
+ syslog(LOG_NOTICE,
+ "using xntpd phase-lock loop");
#endif /* KERNEL_PLL */
+
+ }
+ break;
+
+ case LOOP_PPSDELAY:
+ pps_delay = *lfp_value;
break;
- default:
+#if defined(PPSCLK)
+ case LOOP_PPSBAUD:
+#if defined(HAVE_TERMIOS)
+ /*
+ * System V TERMIOS serial line parameters
+ * (termios interface)
+ */
+ { struct termios ttyb, *ttyp;
+ if (fdpps == -1)
+ return;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fdpps, ttyp) < 0)
+ return;
+ ttyp->c_cflag = CS8|CLOCAL|CREAD | int_value;
+ if (tcsetattr(fdpps, TCSANOW, ttyp) < 0)
+ return;
+ }
+#endif /* HAVE_TERMIOS */
+#if defined(HAVE_BSD_TTYS)
+
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ */
+ { struct sgttyb ttyb;
+
+ if (fdpps == -1 || ioctl(fdpps, TIOCGETP, &ttyb) < 0)
+ return;
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SYS_BAUD(int_value);
+ if (ioctl(fdpps, TIOCSETP, &ttyb) < 0)
+ return;
+ }
+#endif /* HAVE_BSD_TTYS */
+ pps_baud = int_value;
+ break;
+#endif /* PPSCLK */
+
+ default:
/* sigh */
break;
}
}
-
#if defined(KERNEL_PLL)
/*
* _trap - trap processor for undefined syscalls
@@ -710,3 +869,128 @@ pll_trap()
}
#endif /* KERNEL_PLL */
+#if defined(PPSCLK)
+/*
+ * pps_receive - compute and store 1-pps signal offset
+ *
+ * This routine is called once per second when the 1-pps signal is
+ * present. It calculates the offset of the local clock relative to the
+ * 1-pps signal and saves in a circular buffer for later use. If the
+ * clock line discipline is active, its timestamp is used; otherwise,
+ * the buffer timestamp is used.
+ */
+static void
+pps_receive(rbufp)
+ struct recvbuf *rbufp;
+{
+ u_char *dpt; /* buffer pointer */
+ l_fp ts; /* l_fp temps */
+ int dpend; /* buffer length */
+
+ /*
+ * Set up pointers, check the buffer length, discard intercept
+ * character and convert unix timeval to timestamp format.
+ */
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = rbufp->recv_length;
+#if !defined(HPUXGADGET)
+ dpt++;
+ dpend--;
+#endif /* HPUXGADGET */
+ if (dpend != sizeof(struct timeval) || !buftvtots((char *)dpt, &ts))
+ ts = rbufp->recv_time;
+
+ /*
+ * Correct for uart and os delay and process sample offset.
+ */
+ L_SUB(&ts, &pps_delay);
+ L_NEG(&ts);
+ (void)pps_sample(&ts);
+}
+#endif /* PPSCLK */
+
+#if defined(PPS) || defined(PPSCLK) || defined(PPSPPS)
+/*
+ * pps_sample - process pps sample offset
+ */
+int pps_sample(tsr)
+ l_fp *tsr;
+{
+ int i, j; /* temp ints */
+ LONG sort[NPPS]; /* temp array for sorting */
+ l_fp lftemp, ts; /* l_fp temps */
+ u_fp utemp; /* u_fp temp */
+ LONG ltemp; /* long temp */
+
+ /*
+ * Note the seconds offset is already in the low-order timestamp
+ * doubleword, so all we have to do is sign-extend and invert
+ * it. The resulting offset is believed only if within
+ * CLOCK_MAX.
+ */
+ ts = *tsr;
+ lftemp.l_i = lftemp.l_f = 0;
+ M_ADDF(lftemp.l_i, lftemp.l_f, ts.l_f);
+ if (ts.l_f <= -CLOCK_MAX_F || ts.l_f >= CLOCK_MAX_F) {
+ pps_time = 0;
+ return (-1);
+ }
+
+ /*
+ * Save the sample in a circular buffer for later processing.
+ */
+ nsamples++;
+ i = ((int)(nsamples)) % NPPS;
+ samples[i] = lftemp.l_f;
+ if (i != NPPS-1)
+ return (0);
+
+ /*
+ * When the buffer fills up, construct an array of sorted
+ * samples.
+ */
+ pps_time = current_time;
+ for (i = 0; i < NPPS; i++) {
+ sort[i] = samples[i];
+ for (j = 0; j < i; j++) {
+ if (sort[j] > sort[i]) {
+ ltemp = sort[j];
+ sort[j] = sort[i];
+ sort[i] = ltemp;
+ }
+ }
+ }
+
+ /*
+ * Compute offset as the average of all samples in the filter
+ * less PPS_TRIM samples trimmed from the beginning and end,
+ * dispersion as the difference between max and min of samples
+ * retained. The system stratum, root delay and root dispersion
+ * are also set here.
+ */
+ pps_offset.l_i = pps_offset.l_f = 0;
+ for (i = PPS_TRIM; i < NPPS - PPS_TRIM; i++)
+ M_ADDF(pps_offset.l_i, pps_offset.l_f, sort[i]);
+ if (L_ISNEG(&pps_offset)) {
+ L_NEG(&pps_offset);
+ for (i = 0; i < PPS_FAC; i++)
+ L_RSHIFT(&pps_offset);
+ L_NEG(&pps_offset);
+ } else {
+ for (i = 0; i < PPS_FAC; i++)
+ L_RSHIFT(&pps_offset);
+ }
+ lftemp.l_i = 0;
+ lftemp.l_f = sort[NPPS-1-PPS_TRIM] - sort[PPS_TRIM];
+ pps_dispersion = LFPTOFP(&lftemp);
+#ifdef DEBUG
+ if (debug)
+ printf("pps_filter: %s %s %s\n", lfptoa(&pps_delay, 6),
+ lfptoa(&pps_offset, 6), lfptoa(&lftemp, 5));
+#endif /* DEBUG */
+ record_peer_stats(&loopback_interface->sin, ctlsysstatus(),
+ &pps_offset, 0, pps_dispersion);
+ return (0);
+}
+#endif /* PPS || PPSCLK || PPSPPS */
+
diff --git a/usr.sbin/xntpd/xntpd/ntp_request.c b/usr.sbin/xntpd/xntpd/ntp_request.c
index 5b3d481..355b13b 100644
--- a/usr.sbin/xntpd/xntpd/ntp_request.c
+++ b/usr.sbin/xntpd/xntpd/ntp_request.c
@@ -1,9 +1,10 @@
-/*
+/* ntp_request.c,v 3.1 1993/07/06 01:11:26 jbj Exp
* ntp_request.c - respond to information requests
*/
#include <sys/types.h>
#include <stdio.h>
#include <errno.h>
+#include <sys/ioctl.h>
#include <sys/time.h>
#include "ntpd.h"
@@ -16,9 +17,11 @@
#include "ntp_stdlib.h"
#ifdef KERNEL_PLL
-#include "sys/timex.h"
+#include <sys/timex.h>
+#ifndef NTP_SYSCALLS_LIBC
#define ntp_gettime(t) syscall(SYS_ntp_gettime, (t))
#define ntp_adjtime(t) syscall(SYS_ntp_adjtime, (t))
+#endif
#endif /* KERNEL_PLL */
/*
@@ -61,7 +64,7 @@ static void do_conf P((struct sockaddr_in *, struct interface *, struct req_pkt
static void do_unconf P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void set_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void clr_sys_flag P((struct sockaddr_in *, struct interface *, struct req_pkt *));
-static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, u_long));
+static void setclr_flags P((struct sockaddr_in *, struct interface *, struct req_pkt *, U_LONG));
static void do_monitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_nomonitor P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void list_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *));
@@ -69,8 +72,7 @@ static void do_resaddflags P((struct sockaddr_in *, struct interface *, struct r
static void do_ressubflags P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_unrestrict P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_restrict P((struct sockaddr_in *, struct interface *, struct req_pkt *, int));
-static void mon_getlist_0 P((struct sockaddr_in *, struct interface *, struct req_pkt *));
-static void mon_getlist_1 P((struct sockaddr_in *, struct interface *, struct req_pkt *));
+static void mon_getlist P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void reset_stats P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void reset_peer P((struct sockaddr_in *, struct interface *, struct req_pkt *));
static void do_key_reread P((struct sockaddr_in *, struct interface *, struct req_pkt *));
@@ -125,24 +127,23 @@ static struct req_proc xntp_codes[] = {
{ REQ_RESADDFLAGS, AUTH, sizeof(struct conf_restrict), do_resaddflags },
{ REQ_RESSUBFLAGS, AUTH, sizeof(struct conf_restrict), do_ressubflags },
{ REQ_UNRESTRICT, AUTH, sizeof(struct conf_restrict), do_unrestrict },
- { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist_0 },
- { REQ_MON_GETLIST_1, NOAUTH, 0, mon_getlist_1 },
+ { REQ_MON_GETLIST, NOAUTH, 0, mon_getlist },
{ REQ_RESET_STATS, AUTH, sizeof(struct reset_flags), reset_stats },
{ REQ_RESET_PEER, AUTH, sizeof(struct conf_unpeer), reset_peer },
{ REQ_REREAD_KEYS, AUTH, 0, do_key_reread },
{ REQ_DO_DIRTY_HACK, AUTH, 0, do_dirty_hack },
{ REQ_DONT_DIRTY_HACK, AUTH, 0, dont_dirty_hack },
- { REQ_TRUSTKEY, AUTH, sizeof(u_long), trust_key },
- { REQ_UNTRUSTKEY, AUTH, sizeof(u_long), untrust_key },
+ { REQ_TRUSTKEY, AUTH, sizeof(U_LONG), trust_key },
+ { REQ_UNTRUSTKEY, AUTH, sizeof(U_LONG), untrust_key },
{ REQ_AUTHINFO, NOAUTH, 0, get_auth_info },
{ REQ_TRAPS, NOAUTH, 0, req_get_traps },
{ REQ_ADD_TRAP, AUTH, sizeof(struct conf_trap), req_set_trap },
{ REQ_CLR_TRAP, AUTH, sizeof(struct conf_trap), req_clr_trap },
- { REQ_REQUEST_KEY, AUTH, sizeof(u_long), set_request_keyid },
- { REQ_CONTROL_KEY, AUTH, sizeof(u_long), set_control_keyid },
+ { REQ_REQUEST_KEY, AUTH, sizeof(U_LONG), set_request_keyid },
+ { REQ_CONTROL_KEY, AUTH, sizeof(U_LONG), set_control_keyid },
{ REQ_GET_CTLSTATS, NOAUTH, 0, get_ctl_stats },
{ REQ_GET_LEAPINFO, NOAUTH, 0, get_leap_info },
- { REQ_SET_PRECISION, AUTH, sizeof(long), set_precision },
+ { REQ_SET_PRECISION, AUTH, sizeof(LONG), set_precision },
#ifdef KERNEL_PLL
{ REQ_GET_KERNEL, NOAUTH, 0, get_kernel_info },
#endif /* KERNEL_PLL */
@@ -159,19 +160,19 @@ static struct req_proc xntp_codes[] = {
* Authentication keyid used to authenticate requests. Zero means we
* don't allow writing anything.
*/
-u_long info_auth_keyid;
+U_LONG info_auth_keyid;
/*
* Statistic counters to keep track of requests and responses.
*/
-u_long numrequests; /* number of requests we've received */
-u_long numresppkts; /* number of resp packets sent with data */
+U_LONG numrequests; /* number of requests we've received */
+U_LONG numresppkts; /* number of resp packets sent with data */
-u_long errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
+U_LONG errorcounter[INFO_ERR_AUTH+1]; /* lazy way to count errors, indexed */
/* by the error code */
-#ifdef KERNEL_PLL
+#if defined(KERNEL_PLL) && !defined(NTP_SYSCALLS_LIBC)
extern int syscall P((int, void *, ...));
#endif /* KERNEL_PLL */
@@ -188,33 +189,18 @@ extern int debug;
/*
* Imported from the timer module
*/
-extern u_long current_time;
+extern U_LONG current_time;
/*
* Imported from ntp_loopfilter.c
*/
extern int pll_control;
-extern int pll_enable;
-extern int pps_control;
-
-/*
- * Imported from ntp_monitor.c
- */
-extern int mon_enabled;
-
-/*
- * Imported from ntp_util.c
- */
-extern int stats_control;
-
-extern struct peer *peer_hash[];
-extern struct peer *sys_peer;
/*
* A hack. To keep the authentication module clear of xntp-ism's, we
* include a time reset variable for its stats here.
*/
-static u_long auth_timereset;
+static U_LONG auth_timereset;
/*
* Response packet used by these routines. Also some state information
@@ -274,7 +260,7 @@ req_ack(srcadr, inter, inpkt, errcode)
/*
* send packet and bump counters
*/
- sendpkt(srcadr, inter, -1, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
+ sendpkt(srcadr, inter, (struct pkt *)&rpkt, RESP_HEADER_SIZE);
errorcounter[errcode]++;
}
@@ -338,7 +324,7 @@ more_pkt()
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, MORE_BIT);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
- sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
+ sendpkt(toaddr, frominter, (struct pkt *)&rpkt,
RESP_HEADER_SIZE+databytes);
numresppkts++;
@@ -404,7 +390,7 @@ flush_pkt()
rpkt.rm_vn_mode = RM_VN_MODE(RESP_BIT, 0);
rpkt.auth_seq = AUTH_SEQ(0, seqno);
rpkt.err_nitems = htons((u_short)nitems);
- sendpkt(toaddr, frominter, -1, (struct pkt *)&rpkt,
+ sendpkt(toaddr, frominter, (struct pkt *)&rpkt,
RESP_HEADER_SIZE+databytes);
numresppkts++;
}
@@ -497,18 +483,20 @@ process_private(rbufp, mod_okay)
* time stamp.
*/
if (proc->needs_auth) {
- l_fp ftmp;
+ register U_LONG tmp_ui;
+ register U_LONG tmp_uf;
/*
* If this guy is restricted from doing this, don't let him
* If wrong key was used, or packet doesn't have mac, return.
*/
- if (!INFO_IS_AUTH(inpkt->auth_seq) || info_auth_keyid == 0
+ if (!INFO_IS_AUTH(inpkt->auth_seq)
+ || info_auth_keyid == 0
|| ntohl(inpkt->keyid) != info_auth_keyid) {
#ifdef DEBUG
if (debug > 4)
printf(
- "failed auth %d info_auth_keyid %lu pkt keyid %u\n",
+ "failed auth %d info_auth_keyid %u pkt keyid %u\n",
INFO_IS_AUTH(inpkt->auth_seq),
info_auth_keyid, ntohl(inpkt->keyid));
#endif
@@ -518,8 +506,8 @@ process_private(rbufp, mod_okay)
if (rbufp->recv_length > REQ_LEN_MAC) {
#ifdef DEBUG
if (debug > 4)
- printf("bad pkt length %d\n",
- rbufp->recv_length);
+ printf("failed pkt length pkt %d req %d too long\n",
+ rbufp->recv_length, REQ_LEN_MAC);
#endif
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
@@ -537,12 +525,15 @@ process_private(rbufp, mod_okay)
* calculate absolute time difference between xmit time stamp
* and receive time stamp. If too large, too bad.
*/
- NTOHL_FP(&inpkt->tstamp, &ftmp);
- L_SUB(&ftmp, &rbufp->recv_time);
- if (L_ISNEG(&ftmp))
- L_NEG(&ftmp);
+ tmp_ui = ntohl(inpkt->tstamp.l_ui);
+ tmp_uf = ntohl(inpkt->tstamp.l_uf);
+ M_SUB(tmp_ui, tmp_uf, rbufp->recv_time.l_ui,
+ rbufp->recv_time.l_uf);
+ if (M_ISNEG(tmp_ui, tmp_uf))
+ M_NEG(tmp_ui, tmp_uf);
- if (ftmp.l_ui >= INFO_TS_MAXSKEW_UI) {
+ if (M_ISHIS(tmp_ui, tmp_uf,
+ INFO_TS_MAXSKEW_UI, INFO_TS_MAXSKEW_UF)) {
/*
* He's a loser. Tell him.
*/
@@ -599,6 +590,8 @@ peer_list(srcadr, inter, inpkt)
register struct info_peer_list *ip;
register struct peer *pp;
register int i;
+ extern struct peer *peer_hash[];
+ extern struct peer *sys_peer;
ip = (struct info_peer_list *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_peer_list));
@@ -637,6 +630,8 @@ peer_list_sum(srcadr, inter, inpkt)
register struct info_peer_summary *ips;
register struct peer *pp;
register int i;
+ extern struct peer *peer_hash[];
+ extern struct peer *sys_peer;
#ifdef DEBUG
if (debug > 2)
@@ -652,14 +647,10 @@ peer_list_sum(srcadr, inter, inpkt)
if (debug > 3)
printf("sum: got one\n");
#endif
- ips->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- pp->dstadr->bcast.sin_addr.s_addr:
- pp->cast_flags ?
- pp->dstadr->sin.sin_addr.s_addr ?
- pp->dstadr->sin.sin_addr.s_addr:
- pp->dstadr->bcast.sin_addr.s_addr:
- 1 : 5;
+ if (pp->dstadr == any_interface)
+ ips->dstadr = 0;
+ else
+ ips->dstadr = pp->dstadr->sin.sin_addr.s_addr;
ips->srcadr = pp->srcadr.sin_addr.s_addr;
ips->srcport = pp->srcadr.sin_port;
ips->stratum = pp->stratum;
@@ -723,14 +714,7 @@ peer_info (srcadr, inter, inpkt)
ipl++;
if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0)
continue;
- ip->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- pp->dstadr->bcast.sin_addr.s_addr:
- pp->cast_flags ?
- pp->dstadr->sin.sin_addr.s_addr ?
- pp->dstadr->sin.sin_addr.s_addr:
- pp->dstadr->bcast.sin_addr.s_addr:
- 2 : 6;
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
ip->srcadr = NSRCADR(&pp->srcadr);
ip->srcport = NSRCPORT(&pp->srcadr);
ip->flags = 0;
@@ -761,7 +745,7 @@ peer_info (srcadr, inter, inpkt)
ip->reach = pp->reach;
ip->unreach = pp->unreach;
ip->flash = pp->flash;
- ip->estbdelay = HTONS_FP(pp->estbdelay);
+ ip->estbdelay = htonl(pp->estbdelay);
ip->ttl = pp->ttl;
ip->associd = htons(pp->associd);
ip->rootdelay = HTONS_FP(pp->rootdelay);
@@ -821,14 +805,7 @@ peer_stats (srcadr, inter, inpkt)
ipl++;
if ((pp = findexistingpeer(&addr, (struct peer *)0)) == 0)
continue;
- ip->dstadr = (pp->processed) ?
- pp->cast_flags == MDF_BCAST ?
- pp->dstadr->bcast.sin_addr.s_addr:
- pp->cast_flags ?
- pp->dstadr->sin.sin_addr.s_addr ?
- pp->dstadr->sin.sin_addr.s_addr:
- pp->dstadr->bcast.sin_addr.s_addr:
- 3 : 7;
+ ip->dstadr = NSRCADR(&pp->dstadr->sin);
ip->srcadr = NSRCADR(&pp->srcadr);
ip->srcport = NSRCPORT(&pp->srcadr);
ip->flags = 0;
@@ -851,13 +828,21 @@ peer_stats (srcadr, inter, inpkt)
= htonl(pp->event_timer.event_time - current_time);
ip->timereachable = htonl(current_time - pp->timereachable);
ip->sent = htonl(pp->sent);
+ ip->received = htonl(pp->received);
ip->processed = htonl(pp->processed);
+ ip->badlength = 0;
ip->badauth = htonl(pp->badauth);
ip->bogusorg = htonl(pp->bogusorg);
ip->oldpkt = htonl(pp->oldpkt);
+ ip->baddelay = 0;
+ ip->seldelay = 0;
ip->seldisp = htonl(pp->seldisptoolarge);
ip->selbroken = htonl(pp->selbroken);
+ ip->selold = htonl(pp->seltooold);
ip->candidate = pp->candidate;
+ ip->falseticker = 0;
+ ip->select = pp->select;
+ ip->select_total = 0;
ip = (struct info_peer_stats *)more_pkt();
}
flush_pkt();
@@ -883,16 +868,14 @@ sys_info(srcadr, inter, inpkt)
extern s_char sys_precision;
extern s_fp sys_rootdelay;
extern u_fp sys_rootdispersion;
- extern u_long sys_refid;
+ extern U_LONG sys_refid;
extern l_fp sys_reftime;
extern u_char sys_poll;
extern struct peer *sys_peer;
extern int sys_bclient;
- extern s_fp sys_bdelay;
+ extern U_LONG sys_bdelay;
extern int sys_authenticate;
- extern u_long sys_authdelay;
- extern u_fp clock_stability;
- extern s_fp clock_frequency;
+ extern U_LONG sys_authdelay;
is = (struct info_sys *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys));
@@ -909,8 +892,6 @@ sys_info(srcadr, inter, inpkt)
is->precision = sys_precision;
is->rootdelay = htonl(sys_rootdelay);
is->rootdispersion = htonl(sys_rootdispersion);
- is->frequency = htonl(clock_frequency);
- is->stability = htonl(clock_stability);
is->refid = sys_refid;
HTONL_FP(&sys_reftime, &is->reftime);
@@ -920,20 +901,9 @@ sys_info(srcadr, inter, inpkt)
if (sys_bclient)
is->flags |= INFO_FLAG_BCLIENT;
if (sys_authenticate)
- is->flags |= INFO_FLAG_AUTHENTICATE;
- if (pll_enable)
- is->flags |= INFO_FLAG_PLL;
- if (pll_control)
- is->flags |= INFO_FLAG_PLL_SYNC;
- if (pps_control)
- is->flags |= INFO_FLAG_PPS_SYNC;
- if (mon_enabled != MON_OFF)
- is->flags |= INFO_FLAG_MONITOR;
- if (stats_control)
- is->flags |= INFO_FLAG_FILEGEN;
- is->bdelay = HTONS_FP(sys_bdelay);
+ is->flags |= INFO_FLAG_AUTHENABLE;
+ HTONL_UF(sys_bdelay, &is->bdelay);
HTONL_UF(sys_authdelay, &is->authdelay);
-
(void) more_pkt();
flush_pkt();
}
@@ -953,15 +923,15 @@ sys_stats(srcadr, inter, inpkt)
/*
* Importations from the protocol module
*/
- extern u_long sys_stattime;
- extern u_long sys_badstratum;
- extern u_long sys_oldversionpkt;
- extern u_long sys_newversionpkt;
- extern u_long sys_unknownversion;
- extern u_long sys_badlength;
- extern u_long sys_processed;
- extern u_long sys_badauth;
- extern u_long sys_limitrejected;
+ extern U_LONG sys_stattime;
+ extern U_LONG sys_badstratum;
+ extern U_LONG sys_oldversionpkt;
+ extern U_LONG sys_newversionpkt;
+ extern U_LONG sys_unknownversion;
+ extern U_LONG sys_badlength;
+ extern U_LONG sys_processed;
+ extern U_LONG sys_badauth;
+ extern U_LONG sys_limitrejected;
ss = (struct info_sys_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_sys_stats));
@@ -998,10 +968,10 @@ mem_stats(srcadr, inter, inpkt)
*/
extern int peer_hash_count[HASH_SIZE];
extern int peer_free_count;
- extern u_long peer_timereset;
- extern u_long findpeer_calls;
- extern u_long peer_allocations;
- extern u_long peer_demobilizations;
+ extern U_LONG peer_timereset;
+ extern U_LONG findpeer_calls;
+ extern U_LONG peer_allocations;
+ extern U_LONG peer_demobilizations;
extern int total_peer_structs;
ms = (struct info_mem_stats *)prepare_pkt(srcadr, inter, inpkt,
@@ -1040,18 +1010,18 @@ io_stats(srcadr, inter, inpkt)
/*
* Importations from the io module
*/
- extern u_long io_timereset;
- extern u_long full_recvbufs;
- extern u_long free_recvbufs;
- extern u_long total_recvbufs;
- extern u_long lowater_additions;
- extern u_long packets_dropped;
- extern u_long packets_ignored;
- extern u_long packets_received;
- extern u_long packets_sent;
- extern u_long packets_notsent;
- extern u_long handler_calls;
- extern u_long handler_pkts;
+ extern U_LONG io_timereset;
+ extern U_LONG full_recvbufs;
+ extern U_LONG free_recvbufs;
+ extern U_LONG total_recvbufs;
+ extern U_LONG lowater_additions;
+ extern U_LONG packets_dropped;
+ extern U_LONG packets_ignored;
+ extern U_LONG packets_received;
+ extern U_LONG packets_sent;
+ extern U_LONG packets_notsent;
+ extern U_LONG handler_calls;
+ extern U_LONG handler_pkts;
io = (struct info_io_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_io_stats));
@@ -1088,10 +1058,10 @@ timer_stats(srcadr, inter, inpkt)
/*
* Importations from the timer module
*/
- extern u_long alarm_overflow;
- extern u_long timer_timereset;
- extern u_long timer_overflows;
- extern u_long timer_xmtcalls;
+ extern U_LONG alarm_overflow;
+ extern U_LONG timer_timereset;
+ extern U_LONG timer_overflows;
+ extern U_LONG timer_xmtcalls;
ts = (struct info_timer_stats *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_timer_stats));
@@ -1123,8 +1093,8 @@ loop_info(srcadr, inter, inpkt)
*/
extern l_fp last_offset;
extern s_fp drift_comp;
- extern int tc_counter;
- extern u_long last_time;
+ extern int time_constant;
+ extern U_LONG watchdog_timer;
li = (struct info_loop *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_loop));
@@ -1132,8 +1102,8 @@ loop_info(srcadr, inter, inpkt)
HTONL_FP(&last_offset, &li->last_offset);
FPTOLFP(drift_comp, &tmp);
HTONL_FP(&tmp, &li->drift_comp);
- li->compliance = htonl(tc_counter);
- li->watchdog_timer = htonl(current_time - last_time);
+ li->compliance = htonl(time_constant);
+ li->watchdog_timer = htonl(watchdog_timer);
(void) more_pkt();
flush_pkt();
@@ -1171,7 +1141,7 @@ do_conf(srcadr, inter, inpkt)
&& cp->hmode != MODE_CLIENT
&& cp->hmode != MODE_BROADCAST)
fl = 1;
- if (cp->flags & ~(CONF_FLAG_AUTHENABLE | CONF_FLAG_PREFER))
+ if (cp->flags & ~(CONF_FLAG_AUTHENABLE|CONF_FLAG_PREFER))
fl = 1;
cp++;
}
@@ -1297,7 +1267,7 @@ set_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, 1);
+ setclr_flags(srcadr, inter, inpkt, (U_LONG)1);
}
@@ -1310,7 +1280,7 @@ clr_sys_flag(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- setclr_flags(srcadr, inter, inpkt, 0);
+ setclr_flags(srcadr, inter, inpkt, (U_LONG)0);
}
@@ -1322,9 +1292,9 @@ setclr_flags(srcadr, inter, inpkt, set)
struct sockaddr_in *srcadr;
struct interface *inter;
struct req_pkt *inpkt;
- u_long set;
+ U_LONG set;
{
- register u_long flags;
+ register U_LONG flags;
if (INFO_NITEMS(inpkt->err_nitems) > 1) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
@@ -1333,23 +1303,21 @@ setclr_flags(srcadr, inter, inpkt, set)
flags = ((struct conf_sys_flags *)inpkt->data)->flags;
- if (flags & ~(SYS_FLAG_BCLIENT | SYS_FLAG_AUTHENTICATE |
- SYS_FLAG_PLL | SYS_FLAG_MONITOR |
- SYS_FLAG_FILEGEN)) {
+ if (flags
+ & ~(SYS_FLAG_BCLIENT | SYS_FLAG_MCLIENT | SYS_FLAG_AUTHENTICATE)) {
req_ack(srcadr, inter, inpkt, INFO_ERR_FMT);
return;
}
if (flags & SYS_FLAG_BCLIENT)
proto_config(PROTO_BROADCLIENT, set);
+ if (flags & SYS_FLAG_MCLIENT)
+ if (set)
+ proto_config(PROTO_MULTICAST_ADD, INADDR_NTP);
+ else
+ proto_config(PROTO_MULTICAST_DEL, INADDR_NTP);
if (flags & SYS_FLAG_AUTHENTICATE)
proto_config(PROTO_AUTHENTICATE, set);
- if (flags & SYS_FLAG_PLL)
- proto_config(PROTO_PLL, set);
- if (flags & SYS_FLAG_MONITOR)
- proto_config(PROTO_MONITOR, set);
- if (flags & SYS_FLAG_FILEGEN)
- proto_config(PROTO_FILEGEN, set);
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -1488,7 +1456,7 @@ do_restrict(srcadr, inter, inpkt, op)
bad = 1;
if (cr->flags & ~(RES_ALLFLAGS))
bad = 1;
- if (cr->addr == htonl(INADDR_ANY) && cr->mask != htonl(INADDR_ANY))
+ if (cr->addr == INADDR_ANY && cr->mask != INADDR_ANY)
bad = 1;
cr++;
}
@@ -1524,7 +1492,7 @@ do_restrict(srcadr, inter, inpkt, op)
* mon_getlist - return monitor data
*/
static void
-mon_getlist_0(srcadr, inter, inpkt)
+mon_getlist(srcadr, inter, inpkt)
struct sockaddr_in *srcadr;
struct interface *inter;
struct req_pkt *inpkt;
@@ -1536,7 +1504,7 @@ mon_getlist_0(srcadr, inter, inpkt)
#ifdef DEBUG
if (debug > 2)
- printf("wants monitor 0 list\n");
+ printf("wants monitor list\n");
#endif
if (!mon_enabled) {
req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
@@ -1564,57 +1532,6 @@ mon_getlist_0(srcadr, inter, inpkt)
}
/*
- * mon_getlist - return monitor data
- */
-static void
-mon_getlist_1(srcadr, inter, inpkt)
- struct sockaddr_in *srcadr;
- struct interface *inter;
- struct req_pkt *inpkt;
-{
- register struct info_monitor_1 *im;
- register struct mon_data *md;
- extern struct mon_data mon_mru_list;
- extern int mon_enabled;
-
-#ifdef DEBUG
- if (debug > 2)
- printf("wants monitor 1 list\n");
-#endif
- if (!mon_enabled) {
- req_ack(srcadr, inter, inpkt, INFO_ERR_NODATA);
- return;
- }
-
- im = (struct info_monitor_1 *)prepare_pkt(srcadr, inter, inpkt,
- sizeof(struct info_monitor_1));
- for (md = mon_mru_list.mru_next; md != &mon_mru_list && im != 0;
- md = md->mru_next) {
- im->lasttime = htonl(current_time - md->lasttime);
- im->firsttime = htonl(current_time - md->firsttime);
- if (md->lastdrop)
- im->lastdrop = htonl(current_time - md->lastdrop);
- else
- im->lastdrop = 0;
- im->count = htonl(md->count);
- im->addr = md->rmtadr;
- im->daddr = md->cast_flags == MDF_BCAST ?
- md->interface->bcast.sin_addr.s_addr :
- md->cast_flags ?
- md->interface->sin.sin_addr.s_addr ?
- md->interface->sin.sin_addr.s_addr :
- md->interface->bcast.sin_addr.s_addr :
- 4;
- im->flags = md->cast_flags;
- im->port = md->rmtport;
- im->mode = md->mode;
- im->version = md->version;
- im = (struct info_monitor_1 *)more_pkt();
- }
- flush_pkt();
-}
-
-/*
* Module entry points and the flags they correspond with
*/
struct reset_entry {
@@ -1642,7 +1559,7 @@ reset_stats(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- u_long flags;
+ U_LONG flags;
struct reset_entry *rent;
if (INFO_NITEMS(inpkt->err_nitems) > 1) {
@@ -1799,11 +1716,11 @@ do_trustkey(srcadr, inter, inpkt, trust)
struct req_pkt *inpkt;
int trust;
{
- register u_long *kp;
+ register U_LONG *kp;
register int items;
items = INFO_NITEMS(inpkt->err_nitems);
- kp = (u_long *)inpkt->data;
+ kp = (U_LONG *)inpkt->data;
while (items-- > 0) {
authtrust(*kp, trust);
kp++;
@@ -1827,13 +1744,14 @@ get_auth_info(srcadr, inter, inpkt)
/*
* Importations from the authentication module
*/
- extern u_long authnumkeys;
- extern u_long authnumfreekeys;
- extern u_long authkeylookups;
- extern u_long authkeynotfound;
- extern u_long authencryptions;
- extern u_long authdecryptions;
- extern u_long authkeyuncached;
+ extern U_LONG authnumkeys;
+ extern U_LONG authnumfreekeys;
+ extern U_LONG authkeylookups;
+ extern U_LONG authkeynotfound;
+ extern U_LONG authencryptions;
+ extern U_LONG authdecryptions;
+ extern U_LONG authdecryptok;
+ extern U_LONG authkeyuncached;
ia = (struct info_auth *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_auth));
@@ -1844,6 +1762,7 @@ get_auth_info(srcadr, inter, inpkt)
ia->keynotfound = htonl(authkeynotfound);
ia->encryptions = htonl(authencryptions);
ia->decryptions = htonl(authdecryptions);
+ ia->decryptok = htonl(authdecryptok);
ia->keyuncached = htonl(authkeyuncached);
ia->timereset = htonl(current_time - auth_timereset);
@@ -1863,16 +1782,18 @@ reset_auth_stats()
/*
* Importations from the authentication module
*/
- extern u_long authkeylookups;
- extern u_long authkeynotfound;
- extern u_long authencryptions;
- extern u_long authdecryptions;
- extern u_long authkeyuncached;
+ extern U_LONG authkeylookups;
+ extern U_LONG authkeynotfound;
+ extern U_LONG authencryptions;
+ extern U_LONG authdecryptions;
+ extern U_LONG authdecryptok;
+ extern U_LONG authkeyuncached;
authkeylookups = 0;
authkeynotfound = 0;
authencryptions = 0;
authdecryptions = 0;
+ authdecryptok = 0;
authkeyuncached = 0;
auth_timereset = current_time;
}
@@ -1918,7 +1839,7 @@ req_get_traps(srcadr, inter, inpkt)
it->settime = htonl(current_time - tr->tr_settime);
it->origtime = htonl(current_time - tr->tr_origtime);
it->resets = htonl(tr->tr_resets);
- it->flags = htonl((u_long)tr->tr_flags);
+ it->flags = htonl((U_LONG)tr->tr_flags);
it = (struct info_trap *)more_pkt();
}
}
@@ -2032,7 +1953,7 @@ set_request_keyid(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- u_long keyid;
+ U_LONG keyid;
/*
* Restrict ourselves to one item only.
@@ -2042,7 +1963,7 @@ set_request_keyid(srcadr, inter, inpkt)
return;
}
- keyid = ntohl(*((u_long *)(inpkt->data)));
+ keyid = ntohl(*((U_LONG *)(inpkt->data)));
info_auth_keyid = keyid;
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2058,8 +1979,8 @@ set_control_keyid(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- u_long keyid;
- extern u_long ctl_auth_keyid;
+ U_LONG keyid;
+ extern U_LONG ctl_auth_keyid;
/*
* Restrict ourselves to one item only.
@@ -2069,7 +1990,7 @@ set_control_keyid(srcadr, inter, inpkt)
return;
}
- keyid = ntohl(*((u_long *)(inpkt->data)));
+ keyid = ntohl(*((U_LONG *)(inpkt->data)));
ctl_auth_keyid = keyid;
req_ack(srcadr, inter, inpkt, INFO_OKAY);
}
@@ -2090,21 +2011,21 @@ get_ctl_stats(srcadr, inter, inpkt)
/*
* Importations from the control module
*/
- extern u_long ctltimereset;
- extern u_long numctlreq;
- extern u_long numctlbadpkts;
- extern u_long numctlresponses;
- extern u_long numctlfrags;
- extern u_long numctlerrors;
- extern u_long numctltooshort;
- extern u_long numctlinputresp;
- extern u_long numctlinputfrag;
- extern u_long numctlinputerr;
- extern u_long numctlbadoffset;
- extern u_long numctlbadversion;
- extern u_long numctldatatooshort;
- extern u_long numctlbadop;
- extern u_long numasyncmsgs;
+ extern U_LONG ctltimereset;
+ extern U_LONG numctlreq;
+ extern U_LONG numctlbadpkts;
+ extern U_LONG numctlresponses;
+ extern U_LONG numctlfrags;
+ extern U_LONG numctlerrors;
+ extern U_LONG numctltooshort;
+ extern U_LONG numctlinputresp;
+ extern U_LONG numctlinputfrag;
+ extern U_LONG numctlinputerr;
+ extern U_LONG numctlbadoffset;
+ extern U_LONG numctlbadversion;
+ extern U_LONG numctldatatooshort;
+ extern U_LONG numctlbadop;
+ extern U_LONG numasyncmsgs;
ic = (struct info_control *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_control));
@@ -2153,13 +2074,13 @@ get_leap_info(srcadr, inter, inpkt)
extern u_char leap_indicator;
extern u_char leap_warning;
extern u_char leapbits;
- extern u_long leap_timer;
- extern u_long leap_processcalls;
- extern u_long leap_notclose;
- extern u_long leap_monthofleap;
- extern u_long leap_dayofleap;
- extern u_long leap_hoursfromleap;
- extern u_long leap_happened;
+ extern U_LONG leap_timer;
+ extern U_LONG leap_processcalls;
+ extern U_LONG leap_notclose;
+ extern U_LONG leap_monthofleap;
+ extern U_LONG leap_dayofleap;
+ extern U_LONG leap_hoursfromleap;
+ extern U_LONG leap_happened;
il = (struct info_leap *)prepare_pkt(srcadr, inter, inpkt,
sizeof(struct info_leap));
@@ -2279,7 +2200,7 @@ get_clock_info(srcadr, inter, inpkt)
ic->noresponse = htonl(clock.noresponse);
ic->badformat = htonl(clock.badformat);
ic->baddata = htonl(clock.baddata);
- ic->timestarted = htonl(clock.timereset);
+ ic->timestarted = clock.timereset;
HTONL_FP(&clock.fudgetime1, &ic->fudgetime1);
HTONL_FP(&clock.fudgetime2, &ic->fudgetime2);
ic->fudgeval1 = htonl(clock.fudgeval1);
@@ -2366,9 +2287,9 @@ set_precision(srcadr, inter, inpkt)
struct interface *inter;
struct req_pkt *inpkt;
{
- register long precision;
+ register LONG precision;
- precision = ntohl(*(long *)(inpkt->data));
+ precision = ntohl(*(LONG *)(inpkt->data));
if (INFO_NITEMS(inpkt->err_nitems) > 1 ||
precision > -1 || precision < -20) {
@@ -2434,9 +2355,10 @@ get_clkbug_info(srcadr, inter, inpkt)
if (i > NUMCBUGTIMES)
i = NUMCBUGTIMES;
ic->ntimes = (u_char)i;
- ic->stimes = htonl(bug.stimes);
+ ic->stimes = htonl((U_LONG)bug.stimes & ((1<<i)-1));
while (--i >= 0) {
- HTONL_FP(&bug.times[i], &ic->times[i]);
+ ic->times[i].l_ui = htonl(bug.times[i].l_ui);
+ ic->times[i].l_uf = htonl(bug.times[i].l_uf);
}
ic = (struct info_clkbug *)more_pkt();
diff --git a/usr.sbin/xntpd/xntpd/ntp_unixclock.c b/usr.sbin/xntpd/xntpd/ntp_unixclock.c
index 6b81429..df728f0 100644
--- a/usr.sbin/xntpd/xntpd/ntp_unixclock.c
+++ b/usr.sbin/xntpd/xntpd/ntp_unixclock.c
@@ -1,4 +1,4 @@
-/*
+/* ntp_unixclock.c,v 3.1 1993/07/06 01:11:30 jbj Exp
* ntp_unixclock.c - routines for reading and adjusting a 4BSD-style
* system clock
*/
@@ -9,18 +9,22 @@
#include <sys/stat.h>
#include <sys/time.h>
-#if defined(SYS_HPUX) || defined(sgi) || defined(SYS_BSDI) || defined(SYS_44BSD)
+#if defined(SYS_HPUX) || defined(sgi) || defined(SYS_BSDI)
#include <sys/param.h>
#include <utmp.h>
#endif
+#if defined(HAVE_GETBOOTFILE)
+#include <paths.h>
+#endif
+
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_unixtime.h"
#include "ntp_stdlib.h"
#if defined(HAVE_LIBKVM)
-#if defined(SYS_BSDI) || defined(SYS_44BSD)
+#ifdef SYS_BSDI
#include <sys/proc.h>
#endif /* SYS_BSDI */
#include <kvm.h>
@@ -61,19 +65,19 @@ extern int debug;
* We also remember the clock precision we computed from the kernel in
* case someone asks us.
*/
-extern long adj_precision; /* adj precision in usec (tickadj) */
-extern long tvu_maxslew; /* maximum adjust doable in 1<<CLOCK_ADJ sec (usec) */
+extern LONG adj_precision; /* adj precision in usec (tickadj) */
+extern LONG tvu_maxslew; /* maximum adjust doable in 1<<CLOCK_ADJ sec (usec) */
-extern u_long tsf_maxslew; /* same as above, as long format */
+extern U_LONG tsf_maxslew; /* same as above, as LONG format */
extern l_fp sys_clock_offset; /* correction for current system time */
/*
* Import sys_clock (it is updated in get_systime)
*/
-extern long sys_clock;
+extern LONG sys_clock;
-static void clock_parms P((u_long *, u_long *));
+static void clock_parms P((U_LONG *, U_LONG *));
/*
* init_systime - initialize the system clock support code, return
@@ -97,9 +101,9 @@ static void clock_parms P((u_long *, u_long *));
void
init_systime()
{
- u_long tickadj;
- u_long tick;
- u_long hz;
+ U_LONG tickadj;
+ U_LONG tick;
+ U_LONG hz;
/*
* Obtain the values
@@ -107,7 +111,7 @@ init_systime()
clock_parms(&tickadj, &tick);
#ifdef DEBUG
if (debug)
- printf("kernel vars: tickadj = %ld, tick = %ld\n", tickadj, tick);
+ printf("kernel vars: tickadj = %d, tick = %d\n", tickadj, tick);
#endif
/*
@@ -162,14 +166,14 @@ init_systime()
#ifdef DEBUG
if (debug)
printf(
- "adj_precision = %ld, tvu_maxslew = %ld, tsf_maxslew = 0.%08lx\n",
+ "adj_precision = %d, tvu_maxslew = %d, tsf_maxslew = 0.%08x\n",
adj_precision, tvu_maxslew, tsf_maxslew);
#endif
/*
* Set the current offset to 0
*/
- L_CLR(&sys_clock_offset);
+ sys_clock_offset.l_ui = sys_clock_offset.l_uf = 0;
}
#ifdef HAVE_LIBKVM
@@ -180,8 +184,8 @@ init_systime()
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
static struct nlist nl[] = {
#define N_TICKADJ 0
@@ -261,8 +265,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
*tick = 10000; /* microseconds */
*tickadj = 80; /* microseconds */
@@ -275,13 +279,8 @@ clock_parms(tickadj, tick)
#endif
#ifdef SYS_HPUX
-#if defined(hp9000s300)
#define K_TICKADJ_NAME "_tickadj"
#define K_TICK_NAME "_old_tick"
-#else
-#define K_TICKADJ_NAME "tickadj"
-#define K_TICK_NAME "old_tick"
-#endif
#endif
/* The defaults if not defined previously */
@@ -294,8 +293,8 @@ clock_parms(tickadj, tick)
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
register int i;
int kmem;
@@ -314,7 +313,11 @@ clock_parms(tickadj, tick)
{""},
};
#endif
+#ifdef HAVE_GETBOOTFILE
+ const char *kernelname;
+#else
static char *kernelnames[] = {
+ "/kernel",
"/vmunix",
"/unix",
"/mach",
@@ -326,6 +329,7 @@ clock_parms(tickadj, tick)
#endif
NULL
};
+#endif
struct stat stbuf;
int vars[2];
@@ -336,6 +340,11 @@ clock_parms(tickadj, tick)
* Check to see what to use for the object file for names and get
* the locations of the necessary kernel variables.
*/
+#ifdef HAVE_GETBOOTFILE
+ kernelname = getbootfile();
+ if (kernelname &&
+ ((stat(kernelname, &stbuf) == -1) || (nlist(kernelname, nl) < 0))) {
+#else
for (i = 0; kernelnames[i] != NULL; i++) {
if (stat(kernelnames[i], &stbuf) == -1)
continue;
@@ -343,6 +352,7 @@ clock_parms(tickadj, tick)
break;
}
if (kernelnames[i] == NULL) {
+#endif
syslog(LOG_ERR,
"Clock init couldn't find kernel object file");
exit(3);
@@ -382,8 +392,8 @@ clock_parms(tickadj, tick)
}
close(kmem);
- *tickadj = (u_long)vars[K_TICKADJ];
- *tick = (u_long)vars[K_TICK];
+ *tickadj = (U_LONG)vars[K_TICKADJ];
+ *tick = (U_LONG)vars[K_TICK];
#undef K_TICKADJ
#undef K_TICK
@@ -403,8 +413,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
int hz;
@@ -432,8 +442,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
*tick = 10000;
*tickadj = 150;
@@ -453,8 +463,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
#ifdef RS6000
*tickadj = 1000;
@@ -486,8 +496,8 @@ clock_parms(tickadj, tick)
*/
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
register int i;
int kmem;
@@ -565,8 +575,8 @@ clock_parms(tickadj, tick)
}
close(kmem);
- *tickadj = (u_long)vars[K_TICKADJ];
- *tick = (u_long)(1000000/sysconf(_SC_CLK_TCK));
+ *tickadj = (U_LONG)vars[K_TICKADJ];
+ *tick = (U_LONG)(1000000/sysconf(_SC_CLK_TCK));
#undef K_TICKADJ
#undef N_NAME
@@ -574,18 +584,18 @@ clock_parms(tickadj, tick)
#endif /* SOLARIS */
#ifdef SYS_LINUX
-#include "sys/timex.h"
+#include <sys/timex.h>
static void
clock_parms(tickadj, tick)
- u_long *tickadj;
- u_long *tick;
+ U_LONG *tickadj;
+ U_LONG *tick;
{
struct timex txc;
txc.mode = 0;
__adjtimex(&txc);
- *tickadj = (u_long)1; /* our adjtime is accurate */
- *tick = (u_long)txc.tick;
+ *tickadj = (U_LONG)1; /* our adjtime is accurate */
+ *tick = (U_LONG)txc.tick;
}
#endif /* SYS_LINUX */
diff --git a/usr.sbin/xntpd/xntpd/refclock_trak.c b/usr.sbin/xntpd/xntpd/refclock_trak.c
index d10d752..f2b3eb1 100644
--- a/usr.sbin/xntpd/xntpd/refclock_trak.c
+++ b/usr.sbin/xntpd/xntpd/refclock_trak.c
@@ -1,10 +1,11 @@
/*
- * refclock_trak - clock driver for the TRAK 8820 GPS Station Clock
- *
- * Thanks to Tomoaki TSURUOKA <tsuruoka@nc.fukuoka-u.ac.jp> for the
- * previous version from which this one was developed.
+ * refclock_trak.c - clock driver for the TRAK 8810 GPS STATION CLOCK
+ * Tsuruoka Tomoaki Oct 30, 1993
+ * tsuruoka@nc.fukuoka-u.ac.jp
+ * Faculty of Engineering,
+ * Fukuoka University, Fukuoka, JAPAN
*/
-#if defined(REFCLOCK) && defined(TRAK)
+#if defined(REFCLOCK) && (defined(TRAK) || defined(TRAKCLK) || defined(TRAKPPS))
#include <stdio.h>
#include <ctype.h>
@@ -13,201 +14,494 @@
#include "ntpd.h"
#include "ntp_io.h"
#include "ntp_refclock.h"
+#include "ntp_unixtime.h"
+
+static void gps_send();
+
+#if defined(HAVE_BSD_TTYS)
+#include <sgtty.h>
+#endif /* HAVE_BSD_TTYS */
+
+#if defined(HAVE_SYSV_TTYS)
+#include <termio.h>
+#endif /* HAVE_SYSV_TTYS */
+
+#if defined(STREAM)
+#include <termios.h>
+#include <stropts.h>
+#if defined(TRAKCLK)
+#include <sys/clkdefs.h>
+#endif /* TRAKCLK */
+#endif /* STREAM */
+
+#if defined (TRAKPPS)
+#include <sys/ppsclock.h>
+#endif /* TRAKPPS */
+
#include "ntp_stdlib.h"
/*
- * This driver supports the TRAK 8820 GPS Station Clock. The claimed
- * accuracy at the 1-pps output is 200-300 ns relative to the broadcast
- * signal; however, in most cases the actual accuracy is limited by the
- * precision of the timecode and the latencies of the serial interface
- * and operating system.
- *
- * For best accuracy, this radio requires the LDISC_ACTS line
- * discipline, which captures a timestamp at the '*' on-time character
- * of the timecode. Using this discipline the jitter is in the order of
- * 1 ms and systematic error about 0.5 ms. If unavailable, the buffer
- * timestamp is used, which is captured at the \r ending the timecode
- * message. This introduces a systematic error of 23 character times, or
- * about 24 ms at 9600 bps, together with a jitter well over 8 ms on Sun
- * IPC-class machines.
- *
- * Using the memus, the radio should be set for 9600 bps, one stop bit
- * and no parity. It should be set to operate in computer (no echo)
- * mode. The timecode format includes neither the year nor leap-second
- * warning. No provisions are included in this preliminary version of
- * the driver to read and record detailed internal radio status.
- *
- * In operation, this driver sends a RQTS\r request to the radio at
- * initialization in order to put it in continuous time output mode. The
- * radio then sends the following message once each second:
- *
- * *RQTS U,ddd:hh:mm:ss.0,q<cr><lf>
- *
- * on-time = '*' * ddd = day of year
- * hh:mm:ss = hours, minutes, seconds
- * q = quality indicator (phase error), 0-6:
- * 0 > 20 us
- * 6 > 10 us
- * 5 > 1 us
- * 4 > 100 ns
- * 3 > 10 ns
- * 2 < 10 ns
- *
- * The alarm condition is indicated by '0' at Q, which means the radio
- * has a phase error than 20 usec relative to the broadcast time. The
- * absence of year, DST and leap-second warning in this format is also
- * alarming.
+ * This driver supports the TRAK 8810 GPS Receiver with
+ * Buffered RS-232-C Interface Module.
*
- * The continuous time mode is disabled using the RQTX<cr> request,
- * following which the radio sends a RQTX DONE<cr><lf> response. In the
- * normal mode, other control and status requests are effective,
- * including the leap-second status request RQLS<cr>. The radio responds
- * wtih RQLS yy,mm,dd<cr><lf>, where yy,mm,dd are the year, month and
- * day. Presumably, this gives the epoch of the next leap second,
- * RQLS 00,00,00 if none is specified in the GPS message. Specified in
- * this form, the information is generally useless and is ignored by
- * the driver.
+ * Most of codes are copied from refclock_as2201.c, Thanks a lot.
*
- * Fudge Factors
+ * The program expects the radio responses once per seccond
+ * ( by "rqts,u" command or panel control )
+ * of the form "*RQTS U,ddd:hh:mm:ss.0,Q\r\n for UTC" where
+ * ddd= day of year
+ * hh= hours
+ * mm= minutes
+ * ss= seconds
+ * Q= Quality byte. Q=0 Phase error > 20 us
+ * Q=6 Pahse error < 20 us
+ * > 10 us
+ * Q=5 Pahse error < 10 us
+ * > 1 us
+ * Q=4 Pahse error < 1 us
+ * > 100 ns
+ * Q=3 Pahse error < 100 ns
+ * > 10 ns
+ * Q=2 Pahse error < 10 ns
+ * (note that my clock almost stable at 1 us per 10 hours)
*
- * There are no special fudge factors other than the generic.
+ * Request leap second status - if needed.
+ * send: rqls\n
+ * reply: RQLS yy,mm,dd
+ * where: yy is year
+ * mm is month
+ * dd is day of month.baud
+ * Note: Default data is all zeros
+ * i.e. RQLS 00,00,00
*/
/*
- * Interface definitions
+ * Definitions
*/
-#define DEVICE "/dev/trak%d" /* device name and unit */
-#define SPEED232 B9600 /* uart speed (9600 baud) */
-#define PRECISION (-10) /* precision assumed (about 1 ms) */
-#define REFID "TRAK" /* reference ID */
-#define DESCRIPTION "TRACK 8810/8820 Station Clock" /* WRU */
+#define MAXUNITS 4 /* max number of GPS units */
+#define GPS232 "/dev/gps%d" /* name of radio device */
+#define SPEED232 B9600 /* uart speed (9600 bps) */
-#define NSAMPLES 3 /* stages of median filter */
-#define LENTRAK 24 /* timecode length */
-#define C_CTO "RQTS\r" /* start continuous time output */
+/*
+ * Radio interface parameters
+ */
+#define GPSPRECISION (-20) /* precision assumed (about 1 us) */
+#define GPSREFID "GPS" /* reference id */
+#define GPSDESCRIPTION "TRAK 8810 GPS station clock" /* who we are */
+#define GPSHSREFID 0x7f7f020a /* 127.127.2.10 refid hi strata */
+#define GMT 0 /* hour offset from Greenwich */
+#define NCODES 3 /* stages of median filter */
+#define LENTOC 25 /* *RQTS U,ddd:hh:mm:ss.0,Q datecode length */
+#define BMAX 100 /* timecode buffer length */
+#define CODEDIFF 0x20000000 /* 0.125 seconds as an l_fp fraction */
+
+/*
+ * Hack to avoid excercising the multiplier. I have no pride.
+ */
+#define MULBY10(x) (((x)<<3) + ((x)<<1))
/*
* Imported from ntp_timer module
*/
-extern u_long current_time; /* current time (s) */
+extern U_LONG current_time; /* current time (s) */
/*
- * Imported from ntpd module
+ * Imported from ntp_loopfilter module
*/
-extern int debug; /* global debug flag */
+extern int fdpps; /* pps file descriptor */
/*
- * Unit control structure
+ * Imported from ntpd module
*/
-struct wwvbunit {
- int pollcnt; /* poll message counter */
+extern int debug; /* global debug flag */
- u_char tcswitch; /* timecode switch */
- char qualchar; /* quality indicator */
+/*
+ * GPS unit control structure.
+ */
+struct gpsunit {
+ struct peer *peer; /* associated peer structure */
+ struct refclockio io; /* given to the I/O handler */
+ l_fp lastrec; /* last data receive time */
+ l_fp lastref; /* last timecode time */
+ l_fp offset[NCODES]; /* recent sample offsets */
+ char lastcode[BMAX]; /* last timecode received */
+ u_short polled; /* when polled, means a last sample */
+ u_char lencode; /* length of last received ASCII string */
+ U_LONG lasttime; /* last time clock heard from */
+#ifdef TRAKPPS
+ U_LONG lastev; /* last ppsclock second */
+#endif /* TRAKPPS */
+ u_char unit; /* unit number for this guy */
+ u_char status; /* clock status */
+ u_char lastevent; /* last clock event */
+ u_char reason; /* reason for last abort */
+ u_char year; /* year of eternity */
+ u_short day; /* day of year */
+ u_char hour; /* hour of day */
+ u_char minute; /* minute of hour */
+ u_char second; /* seconds of minute */
+ u_short msec; /* milliseconds of second */
+ u_char leap; /* leap indicators */
+ U_LONG yearstart; /* start of current year */
+ /*
+ * Status tallies
+ */
+ U_LONG polls; /* polls sent */
+ U_LONG noreply; /* no replies to polls */
+ U_LONG coderecv; /* timecodes received */
+ U_LONG badformat; /* bad format */
+ U_LONG baddata; /* bad data */
+ U_LONG timestarted; /* time we started this */
};
+
+/*
+ * Data space for the unit structures. Note that we allocate these on
+ * the fly, but never give them back.
+ */
+static struct gpsunit *gpsunits[MAXUNITS];
+static u_char unitinuse[MAXUNITS];
+
+/*
+ * Keep the fudge factors separately so they can be set even
+ * when no clock is configured.
+ */
+static l_fp fudgefactor[MAXUNITS];
+static u_char stratumtouse[MAXUNITS];
+static u_char sloppyclockflag[MAXUNITS];
+
/*
* Function prototypes
*/
-static int trak_start P((int, struct peer *));
-static void trak_shutdown P((int, struct peer *));
+static void trak_init P(());
+static int trak_start P((u_int, struct peer *));
+static void trak_shutdown P((int));
+static void trak_report_event P((struct gpsunit *, int));
static void trak_receive P((struct recvbuf *));
-static void trak_poll P((int, struct peer *));
+static char trak_process P((struct gpsunit *, l_fp *, u_fp *));
+static void trak_poll P((int unit, struct peer *));
+static void trak_control P((u_int, struct refclockstat *, struct refclockstat *));
+static void trak_buginfo P((int, struct refclockbug *));
/*
* Transfer vector
*/
-struct refclock refclock_trak = {
- trak_start, /* start up driver */
- trak_shutdown, /* shut down driver */
- trak_poll, /* transmit poll message */
- noentry, /* not used (old trak_control) */
- noentry, /* initialize driver (not used) */
- noentry, /* not used (old trak_buginfo) */
- NOFLAGS /* not used */
+struct refclock refclock_trak = {
+ trak_start, trak_shutdown, trak_poll,
+ trak_control, trak_init, trak_buginfo, NOFLAGS
};
+/*
+ * trak_init - initialize internal gps driver data
+ */
+static void
+trak_init()
+{
+ register int i;
+ /*
+ * Just zero the data arrays
+ */
+ memset((char *)gpsunits, 0, sizeof gpsunits);
+ memset((char *)unitinuse, 0, sizeof unitinuse);
+
+ /*
+ * Initialize fudge factors to default.
+ */
+ for (i = 0; i < MAXUNITS; i++) {
+ fudgefactor[i].l_ui = 0;
+ fudgefactor[i].l_uf = 0;
+ stratumtouse[i] = 0;
+ sloppyclockflag[i] = 0;
+ }
+}
+
/*
- * trak_start - open the devices and initialize data for processing
+ * trak_start - open the GPS devices and initialize data for processing
*/
static int
trak_start(unit, peer)
- int unit;
+ u_int unit;
struct peer *peer;
{
- register struct wwvbunit *up;
- struct refclockproc *pp;
- int fd;
- char device[20];
+ register struct gpsunit *gps;
+ register int i;
+ int fd232;
+ char trakdev[20];
+#ifdef TRAKPPS
+ struct ppsclockev ev;
+#endif /* TRAKPPS */
/*
- * Open serial port. The LDISC_ACTS line discipline inserts a
- * timestamp following the "*" on-time character of the
- * timecode.
+ * Check configuration info
*/
- (void)sprintf(device, DEVICE, unit);
- if (!(fd = refclock_open(device, SPEED232, LDISC_ACTS)))
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_start: unit %d invalid", unit);
+ return (0);
+ }
+ if (unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_start: unit %d in use", unit);
return (0);
+ }
/*
- * Allocate and initialize unit structure
+ * Open serial port
*/
- if (!(up = (struct wwvbunit *)
- emalloc(sizeof(struct wwvbunit)))) {
- (void) close(fd);
+ (void) sprintf(trakdev, GPS232, unit);
+ fd232 = open(trakdev, O_RDWR, 0777);
+ if (fd232 == -1) {
+ syslog(LOG_ERR, "trak_start: open of %s: %m", trakdev);
return (0);
}
- memset((char *)up, 0, sizeof(struct wwvbunit));
- pp = peer->procptr;
- pp->io.clock_recv = trak_receive;
- pp->io.srcclock = (caddr_t)peer;
- pp->io.datalen = 0;
- pp->io.fd = fd;
- if (!io_addclock(&pp->io)) {
- (void) close(fd);
- free(up);
- return (0);
+
+#if defined(HAVE_SYSV_TTYS)
+ /*
+ * System V serial line parameters (termio interface)
+ *
+ */
+ { struct termio ttyb;
+ if (ioctl(fd232, TCGETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TCGETA): %m", trakdev);
+ goto screwed;
+ }
+ ttyb.c_iflag = IGNBRK|IGNPAR|ICRNL;
+ ttyb.c_oflag = 0;
+ ttyb.c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyb.c_lflag = ICANON;
+ ttyb.c_cc[VERASE] = ttyb.c_cc[VKILL] = '\0';
+ if (ioctl(fd232, TCSETA, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TCSETA): %m", trakdev);
+ goto screwed;
+ }
+ }
+#endif /* HAVE_SYSV_TTYS */
+#if defined(STREAM)
+ /*
+ * POSIX/STREAMS serial line parameters (termios interface)
+ *
+ * The TRAKCLK option provides timestamping at the driver level.
+ * It requires the tty_clk streams module.
+ *
+ * The TRAKPPS option provides timestamping at the driver level.
+ * It uses a 1-pps signal and level converter (gadget box) and
+ * requires the ppsclock streams module and SunOS 4.1.1 or
+ * later.
+ */
+ { struct termios ttyb, *ttyp;
+
+ ttyp = &ttyb;
+ if (tcgetattr(fd232, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcgetattr(%s): %m", trakdev);
+ goto screwed;
+ }
+ ttyp->c_iflag = IGNBRK|IGNPAR;
+ ttyp->c_oflag = 0;
+ ttyp->c_cflag = SPEED232|CS8|CLOCAL|CREAD;
+ ttyp->c_lflag = ICANON;
+ ttyp->c_cc[VERASE] = ttyp->c_cc[VKILL] = '\0';
+ if (tcsetattr(fd232, TCSANOW, ttyp) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcsetattr(%s): %m", trakdev);
+ goto screwed;
+ }
+ if (tcflush(fd232, TCIOFLUSH) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: tcflush(%s): %m", trakdev);
+ goto screwed;
+ }
+#if defined(TRAKCLK)
+ if (ioctl(fd232, I_PUSH, "clk") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, I_PUSH, clk): %m", trakdev);
+ if (ioctl(fd232, CLK_SETSTR, "*") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, CLK_SETSTR): %m", trakdev);
+#endif /* TRAKCLK */
+#if defined(TRAKPPS)
+ if (ioctl(fd232, I_PUSH, "ppsclock") < 0)
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, I_PUSH, ppsclock): %m", trakdev);
+ else
+ fdpps = fd232;
+#endif /* TRAKPPS */
+ }
+#endif /* STREAM */
+#if defined(HAVE_BSD_TTYS)
+ /*
+ * 4.3bsd serial line parameters (sgttyb interface)
+ *
+ * The TRAKCLK option provides timestamping at the driver level.
+ * It requires the tty_clk line discipline and 4.3bsd or later.
+ */
+ { struct sgttyb ttyb;
+#if defined(TRAKCLK)
+ int ldisc = CLKLDISC;
+#endif /* TRAKCLK */
+
+ if (ioctl(fd232, TIOCGETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCGETP): %m", trakdev);
+ goto screwed;
+ }
+ ttyb.sg_ispeed = ttyb.sg_ospeed = SPEED232;
+#if defined(TRAKCLK)
+ ttyb.sg_erase = ttyb.sg_kill = '\r';
+ ttyb.sg_flags = RAW;
+#else
+ ttyb.sg_erase = ttyb.sg_kill = '\0';
+ ttyb.sg_flags = EVENP|ODDP|CRMOD;
+#endif /* TRAKCLK */
+ if (ioctl(fd232, TIOCSETP, &ttyb) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCSETP): %m", trakdev);
+ goto screwed;
+ }
+#if defined(TRAKCLK)
+ if (ioctl(fd232, TIOCSETD, &ldisc) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, TIOCSETD): %m",trakdev);
+ goto screwed;
+ }
+#endif /* TRAKCLK */
+ }
+#endif /* HAVE_BSD_TTYS */
+
+ /*
+ * Allocate unit structure
+ */
+ if (gpsunits[unit] != 0) {
+ gps = gpsunits[unit]; /* The one we want is okay */
+ } else {
+ for (i = 0; i < MAXUNITS; i++) {
+ if (!unitinuse[i] && gpsunits[i] != 0)
+ break;
+ }
+ if (i < MAXUNITS) {
+ /*
+ * Reclaim this one
+ */
+ gps = gpsunits[i];
+ gpsunits[i] = 0;
+ } else {
+ gps = (struct gpsunit *)
+ emalloc(sizeof(struct gpsunit));
+ }
}
- pp->unitptr = (caddr_t)up;
+ bzero((char *)gps, sizeof(struct gpsunit));
+ gpsunits[unit] = gps;
/*
- * Initialize miscellaneous variables
+ * Set up the structures
*/
- peer->precision = PRECISION;
- pp->clockdesc = DESCRIPTION;
- memcpy((char *)&pp->refid, REFID, 4);
- up->pollcnt = 2;
+ gps->peer = peer;
+ gps->unit = (u_char)unit;
+ gps->timestarted = current_time;
+
+ gps->io.clock_recv = trak_receive;
+ gps->io.srcclock = (caddr_t)gps;
+ gps->io.datalen = 0;
+ gps->io.fd = fd232;
+#ifdef TRAKPPS
+ if (ioctl(fd232, CIOGETEV, (caddr_t)&ev) < 0) {
+ syslog(LOG_ERR,
+ "trak_start: ioctl(%s, CIOGETEV): %m", trakdev);
+ goto screwed;
+ } else
+ gps->lastev = ev.tv.tv_sec;
+#endif /* TRAKPPS */
+ if (!io_addclock(&gps->io)) {
+ goto screwed;
+ }
/*
- * Start continuous time output. If something breaks, fold the
- * tent and go home.
+ * All done. Initialize a few random peer variables, then
+ * return success. Note that root delay and root dispersion are
+ * always zero for this clock.
*/
- if (write(pp->io.fd, C_CTO, sizeof(C_CTO)) != sizeof(C_CTO)) {
- refclock_report(peer, CEVNT_FAULT);
- (void) close(fd);
- free(up);
- return (0);
+ peer->precision = GPSPRECISION;
+ peer->rootdelay = 0;
+ peer->rootdispersion = 0;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(GPSREFID, (char *)&peer->refid, 4);
+ else
+ peer->refid = htonl(GPSHSREFID);
+ unitinuse[unit] = 1;
+ /*
+ * request to give time code
+ */
+ {
+ void gps_send();
+ gps_send(gps,"\rRQTS,U\r");
+ gps_send(gps,"SEL 00\r");
}
+
return (1);
-}
+ /*
+ * Something broke; abandon ship.
+ */
+screwed:
+ (void) close(fd232);
+ return (0);
+}
/*
- * trak_shutdown - shut down the clock
+ * trak_shutdown - shut down a GPS clock
*/
static void
-trak_shutdown(unit, peer)
+trak_shutdown(unit)
int unit;
- struct peer *peer;
{
- register struct wwvbunit *up;
- struct refclockproc *pp;
+ register struct gpsunit *gps;
+ void gps_send();
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_shutdown: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_shutdown: unit %d not in use", unit);
+ return;
+ }
+ gps = gpsunits[unit];
+ /*
+ * request not to give time code any more
+ */
+ gps_send(gps,"RQTX\r");
+ /*
+ * Tell the I/O module to turn us off. We're history.
+ */
+ io_closeclock(&gps->io);
+
+ unitinuse[unit] = 0;
+}
+
+
+/*
+ * trak_report_event - note the occurance of an event
+ *
+ * This routine presently just remembers the report and logs it, but
+ * does nothing heroic for the trap handler.
+ */
+static void
+trak_report_event(gps, code)
+ struct gpsunit *gps;
+ int code;
+{
+ struct peer *peer;
- pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
- io_closeclock(&pp->io);
- free(up);
+ peer = gps->peer;
+ if (gps->status != (u_char)code) {
+ gps->status = (u_char)code;
+ if (code != CEVNT_NOMINAL)
+ gps->lastevent = (u_char)code;
+ syslog(LOG_INFO,
+ "clock %s event %x\n", ntoa(&peer->srcadr), code);
+ }
}
@@ -218,122 +512,495 @@ static void
trak_receive(rbufp)
struct recvbuf *rbufp;
{
- register struct wwvbunit *up;
- struct refclockproc *pp;
- struct peer *peer;
- l_fp trtmp;
- char *dpt, *dpend;
- char qchar;
+ register int i,cmdtype;
+ register struct gpsunit *gps;
- /*
- * Initialize pointers and read the timecode and timestamp. We
- * then chuck out everything, including runts, except one
- * message each poll interval.
- */
- peer = (struct peer *)rbufp->recv_srcclock;
- pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
- pp->lencode = refclock_gtlin(rbufp, pp->lastcode, BMAX,
- &pp->lastrec);
- if (up->tcswitch || pp->lencode < 9)
- return;
- up->tcswitch = 1;
+#if defined(TRAKPPS)
+ struct ppsclockev ev;
+ l_fp trtmp;
+#endif /* TRAKPPS */
+ register u_char *dpt;
+ register u_char *cp;
+ register u_char *dpend;
+ l_fp tstmp;
+ u_fp dispersion;
/*
- * We get a buffer and timestamp following the '*' on-time
- * character. If a valid timestamp, we use that in place of the
- * buffer timestamp and edit out the timestamp for prettyprint
- * billboards.
+ * Get the clock this applies to and pointers to the data.
+ * Edit the timecode to remove control chars and trashbits.
*/
- dpt = pp->lastcode;
- dpend = dpt + pp->lencode;
- if (*dpt == '*' && buftvtots(dpt + 1, &trtmp)) {
- if (trtmp.l_i == pp->lastrec.l_i || trtmp.l_i ==
- pp->lastrec.l_i + 1) {
- pp->lastrec = trtmp;
- dpt += 9;
- while (dpt < dpend)
- *(dpt - 8) = *dpt++;
+ gps = (struct gpsunit *)rbufp->recv_srcclock;
+ dpt = (u_char *)&rbufp->recv_space;
+ dpend = dpt + rbufp->recv_length;
+ cp = (u_char *)gps->lastcode;
+
+ while (dpt < dpend) {
+#ifdef TRAKCLK /* prior to TRAKPPS due to timestamp */
+ if ((*cp = 0x7f & *dpt++) != '*' ) cp++;
+ else if (*cp == '*' ) { /* caught magic character */
+ if ( dpend - dpt < 8) {
+ /* short timestamp */
+ if(debug) puts("gps: short timestamp.");
+ return;
+ }
+ if (!buftvtots(dpt,&gps->lastrec)) {
+ /* screwy timestamp */
+ if(debug) puts("gps: screwy timestamp.");
+ return;
+ }
+ dpt += 8;
}
+#else
+#ifdef TRAKPPS
+ if ((*cp = 0x7f & *dpt++) >= ' ') cp++;
+#else
+ /* both are not specified */
+#endif /* TRAKPPS */
+#endif /* TRAKCLK */
}
- up->pollcnt = 2;
- record_clock_stats(&peer->srcadr, pp->lastcode);
+ *cp = '\0';
+ gps->lencode = cp - (u_char *)gps->lastcode;
+ if (gps->lencode == 0) return;
+
#ifdef DEBUG
if (debug)
- printf("trak: timecode %d %s\n", pp->lencode,
- pp->lastcode);
+ printf("gps: timecode %d %s\n",
+ gps->lencode, gps->lastcode);
#endif
/*
- * We get down to business, check the timecode format and decode
- * its contents. If the timecode has invalid length or is not in
- * proper format, we declare bad format and exit.
+ * We check the timecode format and decode its contents. The
+ * timecode has format *........RQTS U,ddd:hh:mm:ss.0,Q\r\n).
+ * 012345678901234567890123
*/
- if (pp->lencode < LENTRAK) {
- refclock_report(peer, CEVNT_BADREPLY);
+#define RQTS 0
+#define RQLS 1
+ cp = (u_char *)gps->lastcode;
+ gps->leap = 0;
+ cmdtype=0;
+ if(strncmp(cp,"*RQTS",5)==0) {
+ cmdtype=RQTS;
+ cp += 8;
+ }
+ else if(strncmp(cp,"RQTS",4)==0) {
+ cmdtype=RQTS;
+ cp += 7;
+ }
+ else if(strncmp(cp,"RQLS",4)==0) {
+ cmdtype=RQLS;
+ cp += 5;
+ }
+ else
+ return;
+
+ switch( cmdtype ) {
+ case RQTS:
+ /*
+ * Check time code format of TRAK 8810
+ */
+ if( !isdigit(cp[0]) ||
+ !isdigit(cp[1]) ||
+ !isdigit(cp[2]) ||
+ cp[3] != ':' ||
+ !isdigit(cp[4]) ||
+ !isdigit(cp[5]) ||
+ cp[6] != ':' ||
+ !isdigit(cp[7]) ||
+ !isdigit(cp[8]) ||
+ cp[9] != ':' ||
+ !isdigit(cp[10])||
+ !isdigit(cp[11])) {
+ gps->badformat++;
+ trak_report_event(gps, CEVNT_BADREPLY);
+ return;
+ }
+ break;
+ case RQLS:
+ /*
+ * reply for leap second request
+ */
+ if (cp[0] !='0' || cp[1] != '0' ) gps->leap = LEAP_ADDSECOND;
+ return;
+ default:
return;
+
}
/*
- * Timecode format: "*RQTS U,ddd:hh:mm:ss.0,q"
- */
- if (sscanf(pp->lastcode, "*RQTS U,%3d:%2d:%2d:%2d.0,%c",
- &pp->day, &pp->hour, &pp->minute, &pp->second, &qchar) != 5) {
- refclock_report(peer, CEVNT_BADREPLY);
+ * Convert date and check values.
+ */
+ gps->day = cp[0] - '0';
+ gps->day = MULBY10(gps->day) + cp[1] - '0';
+ gps->day = MULBY10(gps->day) + cp[2] - '0';
+ if (gps->day < 1 || gps->day > 366) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADDATE);
+ return;
+ }
+ /*
+ * Convert time and check values.
+ */
+ gps->hour = MULBY10(cp[4] - '0') + cp[5] - '0';
+ gps->minute = MULBY10(cp[7] - '0') + cp[8] - '0';
+ gps->second = MULBY10(cp[10] - '0') + cp[11] - '0';
+ gps->msec = 0;
+ if (gps->hour > 23 || gps->minute > 59 || gps->second > 59) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
return;
}
+ if (!gps->polled) return;
+
/*
- * Decode quality and leap characters. If unsynchronized, set
- * the leap bits accordingly and exit.
+ * Test for synchronization Check for quality byte.
*/
- if (qchar == '0')
- pp->leap = LEAP_NOTINSYNC;
- else {
- pp->leap = 0;
- pp->lasttime = current_time;
+/*
+ switch( cp[15] ) {
+ case '0':
+ if(gps->peer->stratum == stratumtouse[gps->unit]) {
+ gps->peer->stratum = 10 ;
+ bzero(&gps->peer->refid,4);
+ }
+ break;
+ default:
+ if(gps->peer->stratum != stratumtouse[gps->unit]) {
+ gps->peer->stratum = stratumtouse[gps->unit] ;
+ bcopy(GPSREFID,&gps->peer->refid,4);
+ }
+ break;
}
+*/
+ if( cp[15] == '0') /* TRAK derailed from tracking satellites */
+ {
+ gps->leap = LEAP_NOTINSYNC;
+ gps->noreply++;
+ trak_report_event(gps, CEVNT_TIMEOUT);
+ }
+ else
+ {
+ gps->lasttime = current_time;
+ if( gps->lastevent == CEVNT_TIMEOUT ) {
+ gps->status = CEVNT_NOMINAL;
+ trak_report_event(gps, CEVNT_NOMINAL);
+ }
+ }
+
+ /*
+ * Now, compute the reference time value. Use the heavy
+ * machinery for the second, which presumably is the one which
+ * occured at the last pps pulse and which was captured by the
+ * loop_filter module. All we have to do here is present a
+ * reasonable facsimile of the time at that pulse so the clock-
+ * filter and selection machinery declares us truechimer. The
+ * precision offset within the second is really tuned by the
+ * loop_filter module. Note that this code does not yet know how
+ * to do the years and relies on the clock-calendar chip for
+ * sanity.
+ */
+
+#if defined(TRAKPPS)
+
+ /*
+ * timestamp must be greater than previous one.
+ */
+ if (ioctl(fdpps, CIOGETEV, (caddr_t)&ev) >= 0) {
+ ev.tv.tv_sec += (U_LONG)JAN_1970;
+ TVTOTS(&ev.tv,&gps->lastrec);
+ if (gps->lastev < ev.tv.tv_sec) {
+ gps->lastev = ev.tv.tv_sec;
+ } else { /* in case of 1-pps missing */
+ gps->lastev = ev.tv.tv_sec;
+ return;
+ }
+ }
+ else
+ return; /* failed to get timestamp */
+#endif /* TRAKPPS */
+
+ if (!clocktime(gps->day, gps->hour, gps->minute,
+ gps->second, GMT, gps->lastrec.l_ui,
+ &gps->yearstart, &gps->lastref.l_ui)) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
+#ifdef DEBUG
+ if(debug) printf("gps: bad date \n");
+#endif
+ return;
+ }
+ MSUTOTSF(gps->msec, gps->lastref.l_uf);
+ tstmp = gps->lastref;
+
+ L_SUB(&tstmp, &gps->lastrec);
+ L_ADD(&tstmp, &(fudgefactor[gps->unit]));
+ i = ((int)(gps->coderecv)) % NCODES;
+ gps->offset[i] = tstmp;
+ gps->coderecv++;
+#if DEBUG
+ if (debug)
+ printf("gps: times %s %s %s\n",
+ ulfptoa(&gps->lastref, 6), ulfptoa(&gps->lastrec, 6),
+ lfptoa(&tstmp, 6));
+#endif
+/* if( tstmp.l_ui != 0 ) return; something wrong */
/*
- * Process the new sample in the median filter and determine the
- * reference clock offset and dispersion. We use lastrec as both
- * the reference time and receive time in order to avoid being
- * cute, like setting the reference time later than the receive
- * time, which may cause a paranoid protocol module to chuck out
- * the data.
+ * Process the samples in the median filter, add the fudge
+ * factor and pass the offset and dispersion along. We use
+ * lastref as both the reference time and receive time in order
+ * to avoid being cute, like setting the reference time later
+ * than the receive time, which may cause a paranoid protocol
+ * module to chuck out the data.
*/
- if (!refclock_process(pp, NSAMPLES, NSAMPLES)) {
- refclock_report(peer, CEVNT_BADTIME);
+ if (gps->coderecv < NCODES)
+ return;
+ if (!trak_process(gps, &tstmp, &dispersion)) {
+ gps->baddata++;
+ trak_report_event(gps, CEVNT_BADTIME);
return;
}
- refclock_receive(peer, &pp->offset, 0, pp->dispersion,
- &pp->lastrec, &pp->lastrec, pp->leap);
+ refclock_receive(gps->peer, &tstmp, GMT, dispersion,
+ &gps->lastrec, &gps->lastrec, gps->leap);
+ /*
+ * after all, clear polled flag
+ */
+ gps->polled = 0;
}
+/*
+ * ==================================================================
+ * gps_send(gps,cmd) Sends a command to the GPS receiver.
+ * as gps_send(gps,"rqts,u\r");
+ * ==================================================================
+ */
+static void
+gps_send(gps,cmd)
+ struct gpsunit *gps;
+ char *cmd;
+{
+ if (write(gps->io.fd, cmd, strlen(cmd)) == -1) {
+ syslog(LOG_ERR, "gps_send: unit %d: %m", gps->unit);
+ trak_report_event(gps,CEVNT_FAULT);
+ } else {
+ gps->polls++;
+ }
+}
+
+/*
+ * trak_process - process a pile of samples from the clock
+ *
+ * This routine uses a three-stage median filter to calculate offset and
+ * dispersion and reduce jitter. The dispersion is calculated as the
+ * span of the filter (max - min).
+ */
+static char
+trak_process(gps, offset, dispersion)
+ struct gpsunit *gps;
+ l_fp *offset;
+ u_fp *dispersion;
+{
+ register int i, j;
+ register U_LONG tmp_ui, tmp_uf;
+ int not_median1 = -1; /* XXX correct? */
+ int not_median2 = -1; /* XXX correct? */
+ int median;
+ u_fp disp_tmp, disp_tmp2;
+
+ /*
+ * This code implements a three-stage median filter. First, we
+ * check if the samples are within 125 ms of each other. If not,
+ * dump the sample set. We take the median of the three offsets
+ * and use that as the sample offset. There probably is not much
+ * to be gained by a longer filter, since the clock filter in
+ * ntp_proto should do its thing.
+ */
+ disp_tmp2 = 0;
+ for (i = 0; i < NCODES-1; i++) {
+ for (j = i+1; j < NCODES; j++) {
+ tmp_ui = gps->offset[i].l_ui;
+ tmp_uf = gps->offset[i].l_uf;
+ M_SUB(tmp_ui, tmp_uf, gps->offset[j].l_ui,
+ gps->offset[j].l_uf);
+ if (M_ISNEG(tmp_ui, tmp_uf)) {
+ M_NEG(tmp_ui, tmp_uf);
+ }
+ if (tmp_ui != 0 || tmp_uf > CODEDIFF) {
+ return (0);
+ }
+ disp_tmp = MFPTOFP(0, tmp_uf);
+ if (disp_tmp > disp_tmp2) {
+ disp_tmp2 = disp_tmp;
+ not_median1 = i;
+ not_median2 = j;
+ }
+ }
+ }
+ if (gps->lasttime == 0)
+ disp_tmp2 = NTP_MAXDISPERSE;
+ else
+ disp_tmp2 = current_time - gps->lasttime;
+ if (not_median1 == 0) {
+ if (not_median2 == 1)
+ median = 2;
+ else
+ median = 1;
+ } else {
+ median = 0;
+ }
+ *offset = gps->offset[median];
+ *dispersion = disp_tmp2;
+ return (1);
+}
/*
* trak_poll - called by the transmit procedure
+ *
+ * We go to great pains to avoid changing state here, since there may be
+ * more than one eavesdropper receiving the same timecode.
*/
static void
trak_poll(unit, peer)
int unit;
struct peer *peer;
{
- register struct wwvbunit *up;
- struct refclockproc *pp;
+ struct gpsunit *gps;
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_poll: unit %d invalid", unit);
+ return;
+ }
+ if (!unitinuse[unit]) {
+ syslog(LOG_ERR, "trak_poll: unit %d not in use", unit);
+ return;
+ }
+ gps = gpsunits[unit];
+ if ((current_time - gps->lasttime) > 150)
+ trak_report_event(gpsunits[unit], CEVNT_TIMEOUT);
/*
- * We don't really do anything here, except arm the receiving
- * side to capture a sample and check for timeouts.
+ * usually trak_receive can get a timestamp every second
*/
- pp = peer->procptr;
- up = (struct wwvbunit *)pp->unitptr;
- if (up->pollcnt == 0)
- refclock_report(peer, CEVNT_TIMEOUT);
- else
- up->pollcnt--;
- up->tcswitch = 0;
- pp->polls++;
+#if !defined(TRAKPPS) && !defined(TRAKCLK)
+ gettstamp(&gps->lastrec);
+#endif
+ gps->polls++;
+ /*
+ * may be polled every 16 seconds (minpoll 4)
+ */
+ gps->polled = 1;
+}
+
+/*
+ * trak_control - set fudge factors, return statistics
+ */
+static void
+trak_control(unit, in, out)
+ u_int unit;
+ struct refclockstat *in;
+ struct refclockstat *out;
+{
+ register struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_control: unit %d invalid", unit);
+ return;
+ }
+
+ if (in != 0) {
+ if (in->haveflags & CLK_HAVETIME1)
+ fudgefactor[unit] = in->fudgetime1;
+ if (in->haveflags & CLK_HAVEVAL1) {
+ stratumtouse[unit] = (u_char)(in->fudgeval1 & 0xf);
+ if (unitinuse[unit]) {
+ struct peer *peer;
+
+ /*
+ * Should actually reselect clock, but
+ * will wait for the next timecode
+ */
+ gps = gpsunits[unit];
+ peer = gps->peer;
+ peer->stratum = stratumtouse[unit];
+ if (stratumtouse[unit] <= 1)
+ bcopy(GPSREFID, (char *)&peer->refid,
+ 4);
+ else
+ peer->refid = htonl(GPSHSREFID);
+ }
+ }
+ }
+
+ if (out != 0) {
+ out->type = REFCLK_GPS_TRAK;
+ out->haveflags
+ = CLK_HAVETIME1|CLK_HAVEVAL1|CLK_HAVEVAL2;
+ out->clockdesc = GPSDESCRIPTION;
+ out->fudgetime1 = fudgefactor[unit];
+ out->fudgetime2.l_ui = 0;
+ out->fudgetime2.l_uf = 0;
+ out->fudgeval1 = (LONG)stratumtouse[unit];
+ out->fudgeval2 = 0;
+ out->flags = sloppyclockflag[unit];
+ if (unitinuse[unit]) {
+ gps = gpsunits[unit];
+ out->lencode = gps->lencode; /* LENTOC */;
+ out->lastcode = gps->lastcode;
+ out->timereset = current_time - gps->timestarted;
+ out->polls = gps->polls;
+ out->noresponse = gps->noreply;
+ out->badformat = gps->badformat;
+ out->baddata = gps->baddata;
+ out->lastevent = gps->lastevent;
+ out->currentstatus = gps->status;
+ } else {
+ out->lencode = 0;
+ out->lastcode = "";
+ out->polls = out->noresponse = 0;
+ out->badformat = out->baddata = 0;
+ out->timereset = 0;
+ out->currentstatus = out->lastevent = CEVNT_NOMINAL;
+ }
+ }
}
+/*
+ * trak_buginfo - return clock dependent debugging info
+ */
+static void
+trak_buginfo(unit, bug)
+ int unit;
+ register struct refclockbug *bug;
+{
+ register struct gpsunit *gps;
+
+ if (unit >= MAXUNITS) {
+ syslog(LOG_ERR, "trak_buginfo: unit %d invalid", unit);
+ return;
+ }
+
+ if (!unitinuse[unit])
+ return;
+ gps = gpsunits[unit];
+
+ bug->nvalues = 10;
+ bug->ntimes = 5;
+ if (gps->lasttime != 0)
+ bug->values[0] = current_time - gps->lasttime;
+ else
+ bug->values[0] = 0;
+ bug->values[1] = (U_LONG)gps->reason;
+ bug->values[2] = (U_LONG)gps->year;
+ bug->values[3] = (U_LONG)gps->day;
+ bug->values[4] = (U_LONG)gps->hour;
+ bug->values[5] = (U_LONG)gps->minute;
+ bug->values[6] = (U_LONG)gps->second;
+ bug->values[7] = (U_LONG)gps->msec;
+ bug->values[8] = gps->noreply;
+ bug->values[9] = gps->yearstart;
+ bug->stimes = 0x1c;
+ bug->times[0] = gps->lastref;
+ bug->times[1] = gps->lastrec;
+ bug->times[2] = gps->offset[0];
+ bug->times[3] = gps->offset[1];
+ bug->times[4] = gps->offset[2];
+}
#endif
diff --git a/usr.sbin/xntpd/xntpdc/Makefile b/usr.sbin/xntpd/xntpdc/Makefile
new file mode 100644
index 0000000..4f40d70
--- /dev/null
+++ b/usr.sbin/xntpd/xntpdc/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 20:36:45 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= xntpdc
+MAN8= ${.CURDIR}/../doc/xntpdc.8
+CLEANFILES+= .version version.c
+
+SRCS= ntpdc.c ntpdc_ops.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpdc
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/xntpd/xntpdc/ntpdc.c b/usr.sbin/xntpd/xntpdc/ntpdc.c
index 387540b..3113c9f 100644
--- a/usr.sbin/xntpd/xntpdc/ntpdc.c
+++ b/usr.sbin/xntpd/xntpdc/ntpdc.c
@@ -1,4 +1,4 @@
-/*
+/* ntpdc.c,v 3.1 1993/07/06 01:11:59 jbj Exp
* xntpdc - control and monitor your xntpd daemon
*/
#include <stdio.h>
@@ -26,7 +26,7 @@ static char * prompt = "xntpdc> "; /* prompt to ask him about */
/*
* Keyid used for authenticated requests. Obtained on the fly.
*/
-static u_long info_auth_keyid;
+static U_LONG info_auth_keyid;
/*
* Type of key md5 or des
@@ -51,7 +51,7 @@ static void docmd P((char *));
static void tokenize P((char *, char **, int *));
static int findcmd P((char *, struct xcmd *, struct xcmd *, struct xcmd **));
static int getarg P((char *, int, arg_v *));
-static int getnetnum P((char *, u_long *, char *));
+static int getnetnum P((char *, U_LONG *, char *));
static void help P((struct parse *, FILE *));
#if defined(sgi) || defined(SYS_BSDI) || defined(__STDC__)
static int helpsort P((const void *, const void *));
@@ -62,6 +62,7 @@ static void printusage P((struct xcmd *, FILE *));
static void timeout P((struct parse *, FILE *));
static void delay P((struct parse *, FILE *));
static void host P((struct parse *, FILE *));
+static void ntp_poll P((struct parse *, FILE *));
static void keyid P((struct parse *, FILE *));
static void keytype P((struct parse *, FILE *));
static void passwd P((struct parse *, FILE *));
@@ -71,17 +72,17 @@ static void quit P((struct parse *, FILE *));
static void version P((struct parse *, FILE *));
static void warning P((char *, char *, char *));
static void error P((char *, char *, char *));
-static u_long getkeyid P((char *));
+static U_LONG getkeyid P((char *));
/*
* Built-in commands we understand
*/
static struct xcmd builtins[] = {
- { "?", help, { OPT|NTP_STR, NO, NO, NO },
+ { "?", help, { OPT|STR, NO, NO, NO },
{ "command", "", "", "" },
"tell the use and syntax of commands" },
- { "help", help, { OPT|NTP_STR, NO, NO, NO },
+ { "help", help, { OPT|STR, NO, NO, NO },
{ "command", "", "", "" },
"tell the use and syntax of commands" },
{ "timeout", timeout, { OPT|UINT, NO, NO, NO },
@@ -90,16 +91,19 @@ static struct xcmd builtins[] = {
{ "delay", delay, { OPT|INT, NO, NO, NO },
{ "msec", "", "", "" },
"set the delay added to encryption time stamps" },
- { "host", host, { OPT|NTP_STR, NO, NO, NO },
+ { "host", host, { OPT|STR, NO, NO, NO },
{ "hostname", "", "", "" },
"specify the host whose NTP server we talk to" },
- { "passwd", passwd, { OPT|NTP_STR, NO, NO, NO },
+ { "poll", ntp_poll, { OPT|UINT, OPT|STR, NO, NO },
+ { "n", "verbose", "", "" },
+ "poll an NTP server in client mode `n' times" },
+ { "passwd", passwd, { NO, NO, NO, NO },
{ "", "", "", "" },
"specify a password to use for authenticated requests"},
- { "hostnames", hostnames, { OPT|NTP_STR, NO, NO, NO },
+ { "hostnames", hostnames, { OPT|STR, NO, NO, NO },
{ "yes|no", "", "", "" },
"specify whether hostnames or net numbers are printed"},
- { "debug", setdebug, { OPT|NTP_STR, NO, NO, NO },
+ { "debug", setdebug, { OPT|STR, NO, NO, NO },
{ "no|more|less", "", "", "" },
"set/change debugging level" },
{ "quit", quit, { NO, NO, NO, NO },
@@ -108,7 +112,7 @@ static struct xcmd builtins[] = {
{ "keyid", keyid, { OPT|UINT, NO, NO, NO },
{ "key#", "", "", "" },
"set keyid to use for authenticated requests" },
- { "keytype", keytype, { NTP_STR, NO, NO, NO },
+ { "keytype", keytype, { STR, NO, NO, NO },
{ "key type (md5|des)", "", "", "" },
"set key type to use for authenticated requests (des|md5)" },
{ "version", version, { NO, NO, NO, NO },
@@ -126,7 +130,7 @@ static struct xcmd builtins[] = {
#define DEFSTIMEOUT (2) /* 2 second time out after first */
#define DEFDELAY 0x51EB852 /* 20 milliseconds, l_fp fraction */
#define DEFHOST "localhost" /* default host name */
-#define LENHOSTNAME 256 /* host name is 256 characters long */
+#define LENHOSTNAME 256 /* host name is 256 characters LONG */
#define MAXCMDS 100 /* maximum commands on cmd line */
#define MAXHOSTS 100 /* maximum hosts on cmd line */
#define MAXLINE 512 /* maximum line length */
@@ -309,7 +313,7 @@ static int
openhost(hname)
char *hname;
{
- u_long netnum;
+ U_LONG netnum;
char temphost[LENHOSTNAME];
if (server_entry == NULL) {
@@ -425,9 +429,9 @@ getresponse(implcode, reqcode, ritems, rsize, rdata)
/*
* This is pretty tricky. We may get between 1 and many packets
* back in response to the request. We peel the data out of
- * each packet and collect it in one long block. When the last
+ * each packet and collect it in one LONG block. When the last
* packet in the sequence is received we'll know how many we
- * should have had. Note we use one long time out, should reconsider.
+ * should have had. Note we use one LONG time out, should reconsider.
*/
*ritems = 0;
*rsize = 0;
@@ -698,8 +702,7 @@ sendrequest(implcode, reqcode, auth, qitems, qsize, qdata)
* doquery - send a request and process the response
*/
int
-doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata,
- quiet_mask)
+doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata)
int implcode;
int reqcode;
int auth;
@@ -709,7 +712,6 @@ doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata,
int *ritems;
int *rsize;
char **rdata;
- int quiet_mask;
{
int res;
char junk[512];
@@ -753,8 +755,7 @@ doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata,
*/
res = getresponse(implcode, reqcode, ritems, rsize, rdata);
- /* log error message if not told to be quiet */
- if ((res > 0) && (((1 << res) & quiet_mask) == 0)) {
+ if (res > 0) {
switch(res) {
case INFO_ERR_IMPL:
(void) fprintf(stderr,
@@ -763,7 +764,6 @@ doquery(implcode, reqcode, auth, qitems, qsize, qdata, ritems, rsize, rdata,
case INFO_ERR_REQ:
(void) fprintf(stderr,
"***Server doesn't implement this request\n");
- break;
case INFO_ERR_FMT:
(void) fprintf(stderr,
"***Server reports a format error in the received packet (shouldn't happen)\n");
@@ -1030,7 +1030,7 @@ getarg(str, code, argp)
static char *digits = "0123456789";
switch (code & ~OPT) {
- case NTP_STR:
+ case STR:
argp->string = str;
break;
case ADD:
@@ -1081,7 +1081,7 @@ getarg(str, code, argp)
static int
getnetnum(host, num, fullhost)
char *host;
- u_long *num;
+ U_LONG *num;
char *fullhost;
{
struct hostent *hp;
@@ -1089,13 +1089,13 @@ getnetnum(host, num, fullhost)
if (decodenetnum(host, num)) {
if (fullhost != 0) {
(void) sprintf(fullhost,
- "%u.%u.%u.%u", (u_int)((htonl(*num)>>24)&0xff),
- (u_int)((htonl(*num)>>16)&0xff), (u_int)((htonl(*num)>>8)&0xff),
- (u_int)(htonl(*num)&0xff));
+ "%d.%d.%d.%d", ((htonl(*num)>>24)&0xff),
+ ((htonl(*num)>>16)&0xff), ((htonl(*num)>>8)&0xff),
+ (htonl(*num)&0xff));
}
return 1;
} else if ((hp = gethostbyname(host)) != 0) {
- memmove((char *)num, hp->h_addr, sizeof(u_long));
+ memmove((char *)num, hp->h_addr, sizeof(U_LONG));
if (fullhost != 0)
(void) strcpy(fullhost, hp->h_name);
return 1;
@@ -1112,7 +1112,7 @@ getnetnum(host, num, fullhost)
*/
char *
nntohost(netnum)
- u_long netnum;
+ U_LONG netnum;
{
if (!showhostnames)
return numtoa(netnum);
@@ -1267,18 +1267,18 @@ delay(pcmd, fp)
FILE *fp;
{
int isneg;
- u_long val;
+ U_LONG val;
if (pcmd->nargs == 0) {
val = delay_time.l_ui * 1000 + delay_time.l_uf / 4294967;
- (void) fprintf(fp, "delay %lu ms\n", val);
+ (void) fprintf(fp, "delay %d ms\n", val);
} else {
if (pcmd->argval[0].ival < 0) {
isneg = 1;
- val = (u_long)(-pcmd->argval[0].ival);
+ val = (U_LONG)(-pcmd->argval[0].ival);
} else {
isneg = 0;
- val = (u_long)pcmd->argval[0].ival;
+ val = (U_LONG)pcmd->argval[0].ival;
}
delay_time.l_ui = val / 1000;
@@ -1317,6 +1317,19 @@ host(pcmd, fp)
/*
+ * poll - do one (or more) polls of the host via NTP
+ */
+/*ARGSUSED*/
+static void
+ntp_poll(pcmd, fp)
+ struct parse *pcmd;
+ FILE *fp;
+{
+ (void) fprintf(fp, "poll not implemented yet\n");
+}
+
+
+/*
* keyid - get a keyid to use for authenticating requests
*/
static void
@@ -1328,7 +1341,7 @@ keyid(pcmd, fp)
if (info_auth_keyid == 0)
(void) fprintf(fp, "no keyid defined\n");
else
- (void) fprintf(fp, "keyid is %lu\n", info_auth_keyid);
+ (void) fprintf(fp, "keyid is %u\n", info_auth_keyid);
} else {
info_auth_keyid = pcmd->argval[0].uval;
}
@@ -1383,16 +1396,11 @@ passwd(pcmd, fp)
return;
}
}
- if (!interactive) {
- authusekey(info_auth_keyid, info_auth_keytype,
- pcmd->argval[0].string);
- } else {
- pass = getpass("Password: ");
- if (*pass == '\0')
- (void) fprintf(fp, "Password unchanged\n");
- else
- authusekey(info_auth_keyid, info_auth_keytype, pass);
- }
+ pass = getpass("Password: ");
+ if (*pass == '\0')
+ (void) fprintf(fp, "Password unchanged\n");
+ else
+ authusekey(info_auth_keyid, info_auth_keytype, pass);
}
@@ -1507,7 +1515,7 @@ error(fmt, st1, st2)
/*
* getkeyid - prompt the user for a keyid to use
*/
-static u_long
+static U_LONG
getkeyid(prompt)
char *prompt;
{
@@ -1528,5 +1536,5 @@ char *prompt;
*p = '\0';
if (fi != stdin)
fclose(fi);
- return (u_long)atoi(pbuf);
+ return (U_LONG)atoi(pbuf);
}
diff --git a/usr.sbin/xntpd/xntpres/Makefile b/usr.sbin/xntpd/xntpres/Makefile
new file mode 100644
index 0000000..fc41047
--- /dev/null
+++ b/usr.sbin/xntpd/xntpres/Makefile
@@ -0,0 +1,28 @@
+#
+# $Id: Makefile,v 1.1 1993/12/21 20:38:27 wollman Exp $
+#
+
+CFLAGS+= -I${.CURDIR}/../include
+
+.if exists(${.CURDIR}/../lib/obj)
+LDADD+= -L${.CURDIR}/../lib/obj
+DPADD+= -L${.CURDIR}/../lib/obj/libntp.a
+.else
+LDADD+= -L${.CURDIR}/../lib
+DPADD+= -L${.CURDIR}/../lib/libntp.a
+.endif
+
+LDADD+= -lntp
+
+PROG= xntpres
+NOMAN=
+CLEANFILES+= .version version.c
+
+SRCS= xntpres.c version.c
+
+beforedepend: version.c
+
+version.c: ${.CURDIR}/../VERSION
+ ${.CURDIR}/../scripts/mkversion xntpres
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypbind/Makefile b/usr.sbin/ypbind/Makefile
new file mode 100644
index 0000000..0a0b9a4
--- /dev/null
+++ b/usr.sbin/ypbind/Makefile
@@ -0,0 +1,8 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.2 1994/02/17 07:06:06 rgrimes Exp $
+
+PROG= ypbind
+NOMAN=
+CFLAGS+=-DDAEMON
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c
new file mode 100644
index 0000000..73ddcaa
--- /dev/null
+++ b/usr.sbin/ypbind/ypbind.c
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 1992/3 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. 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 1994/08/08 01:03:58 wollman 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 <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>
+
+#ifndef BINDINGDIR
+#define BINDINGDIR "/var/yp/binding"
+#endif
+
+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;
+ 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;
+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;
+
+ bzero((char *)&res, 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];
+
+ bzero((char *)&res, sizeof res);
+ res.ypbind_status = YPBIND_FAIL_VAL;
+
+ for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
+ if( strcmp(ypdb->dom_domain, argp) == 0)
+ break;
+
+ if(ypdb==NULL) {
+ ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ bzero((char *)ypdb, 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;
+
+#if 0
+ delta = ypdb->dom_check_t - ypdb->dom_ask_t;
+ if( !(ypdb->dom_ask_t==0 || delta > 5)) {
+ ypdb->dom_ask_t = time(NULL);
+ /*
+ * Hmm. More than 2 requests in 5 seconds have indicated that my
+ * binding is possibly incorrect. Ok, make myself unalive, and
+ * find out what the actual state is.
+ */
+ if(ypdb->dom_lockfd!=-1)
+ close(ypdb->dom_lockfd);
+ ypdb->dom_lockfd = -1;
+ ypdb->dom_alive = 0;
+ ypdb->dom_lockfd = -1;
+ sprintf(path, "%s/%s.%d", BINDINGDIR, ypdb->dom_domain, ypdb->dom_vers);
+ unlink(path);
+ check++;
+ return NULL;
+ }
+#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 char res;
+
+ bzero((char *)&res, sizeof(res));
+ fromsin = svc_getcaller(transp);
+
+ switch(ypsetmode) {
+ case YPSET_LOCAL:
+ if( fromsin->sin_addr.s_addr != htonl(INADDR_LOOPBACK))
+ return (void *)NULL;
+ break;
+ case YPSET_ALL:
+ break;
+ case YPSET_NO:
+ default:
+ return (void *)NULL;
+ }
+
+ if(ntohs(fromsin->sin_port) >= IPPORT_RESERVED)
+ return (void *)&res;
+
+ if(argp->ypsetdom_vers != YPVERS)
+ return (void *)&res;
+
+ bzero((char *)&bindsin, sizeof bindsin);
+ bindsin.sin_family = AF_INET;
+ bindsin.sin_addr.s_addr = argp->ypsetdom_addr.s_addr;
+ bindsin.sin_port = argp->ypsetdom_port;
+ rpc_received(argp->ypsetdom_domain, &bindsin, 1);
+
+ res = 1;
+ return (void *)&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;
+ }
+ bzero((char *)&argument, sizeof(argument));
+ if (!svc_getargs(transp, xdr_argument, &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)
+char **argv;
+{
+ char path[MAXPATHLEN];
+ struct timeval tv;
+ fd_set fdsr;
+ int width;
+ int i;
+
+ yp_get_default_domain(&domainname);
+ if( domainname[0] == '\0') {
+ fprintf(stderr, "domainname not set. Aborting.\n");
+ exit(1);
+ }
+
+ for(i=1; i<argc; i++) {
+ if( strcmp("-ypset", argv[i]) == 0)
+ ypsetmode = YPSET_ALL;
+ else if (strcmp("-ypsetme", argv[i]) == 0)
+ ypsetmode = YPSET_LOCAL;
+ }
+
+ /* blow away everything in BINDINGDIR */
+
+
+
+#ifdef DAEMON
+ switch(fork()) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ exit(1);
+ default:
+ exit(0);
+ }
+ setsid();
+#endif
+
+ 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;
+ }
+
+ fcntl(rpcsock, F_SETFL, fcntl(rpcsock, F_GETFL, 0) | FNDELAY);
+ i = 1;
+ setsockopt(rpcsock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
+ 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);
+ bzero((char *)ypbindlist, 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);
+
+ width = getdtablesize();
+ while(1) {
+ fdsr = svc_fdset;
+ FD_SET(rpcsock, &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)) {
+ FD_CLR(rpcsock, &fdsr);
+ handle_replies();
+ }
+ svc_getreqset(&fdsr);
+ if(check)
+ checkwork();
+ break;
+ }
+ }
+}
+
+/*
+ * change to do something like this:
+ *
+ * STATE TIME ACTION NEWTIME NEWSTATE
+ * no binding t==* broadcast t=2 no binding
+ * binding t==60 check server t=10 binding
+ * binding t=10 broadcast t=2 no binding
+ */
+checkwork()
+{
+ struct _dom_binding *ypdb;
+ time_t t;
+
+ check = 0;
+
+ time(&t);
+ for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext) {
+ if(ypdb->dom_alive==0 || ypdb->dom_check_t < t) {
+ broadcast(ypdb->dom_domain);
+ time(&t);
+ ypdb->dom_check_t = t + 5;
+ }
+ }
+}
+
+broadcast(dom)
+char *dom;
+{
+ struct rpc_msg rpcmsg;
+ char buf[1400], inbuf[8192];
+ enum clnt_stat st;
+ struct timeval tv;
+ int outlen, i, sock, len;
+ struct sockaddr_in bsin;
+ struct ifconf ifc;
+ struct ifreq ifreq, *ifr;
+ struct in_addr in;
+ AUTH *rpcua;
+ XDR rpcxdr;
+
+ rmtca.xdr_args = xdr_domainname;
+ rmtca.args_ptr = dom;
+
+ bzero((char *)&bsin, sizeof bsin);
+ bsin.sin_family = AF_INET;
+ bsin.sin_port = htons(PMAPPORT);
+
+ bzero((char *)&rpcxdr, sizeof rpcxdr);
+ bzero((char *)&rpcmsg, sizeof rpcmsg);
+
+ rpcua = authunix_create_default();
+ if( rpcua == (AUTH *)NULL) {
+ /*printf("cannot get unix auth\n");*/
+ return RPC_SYSTEMERROR;
+ }
+ rpcmsg.rm_direction = CALL;
+ rpcmsg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+ rpcmsg.rm_call.cb_prog = PMAPPROG;
+ rpcmsg.rm_call.cb_vers = PMAPVERS;
+ rpcmsg.rm_call.cb_proc = PMAPPROC_CALLIT;
+ rpcmsg.rm_call.cb_cred = rpcua->ah_cred;
+ rpcmsg.rm_call.cb_verf = rpcua->ah_verf;
+
+ gettimeofday(&tv, (struct timezone *)0);
+ rpcmsg.rm_xid = (int)dom;
+ tv.tv_usec = 0;
+ xdrmem_create(&rpcxdr, buf, sizeof buf, XDR_ENCODE);
+ if( (!xdr_callmsg(&rpcxdr, &rpcmsg)) ) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ if( (!xdr_rmtcall_args(&rpcxdr, &rmtca)) ) {
+ st = RPC_CANTENCODEARGS;
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ outlen = (int)xdr_getpos(&rpcxdr);
+ xdr_destroy(&rpcxdr);
+ if(outlen<1) {
+ AUTH_DESTROY(rpcua);
+ return st;
+ }
+ AUTH_DESTROY(rpcua);
+
+ /* 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;
+ bsin.sin_addr = in;
+ if( sendto(rpcsock, buf, outlen, 0, (struct sockaddr *)&bsin,
+ sizeof bsin) < 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:
+ bzero((char *)&xdr, sizeof(xdr));
+ bzero((char *)&msg, 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_long))
+ 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;
+}
+
+/*
+ * 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;
+
+ /*printf("returned from %s about %s\n", inet_ntoa(raddrp->sin_addr), dom);*/
+
+ if(dom==NULL)
+ return;
+
+ for(ypdb=ypbindlist; ypdb; ypdb=ypdb->dom_pnext)
+ if( strcmp(ypdb->dom_domain, dom) == 0)
+ break;
+
+ if(ypdb==NULL) {
+ if(force==0)
+ return;
+ ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ bzero((char *)ypdb, sizeof *ypdb);
+ strncpy(ypdb->dom_domain, dom, sizeof ypdb->dom_domain);
+ ypdb->dom_lockfd = -1;
+ ypdb->dom_pnext = ypbindlist;
+ ypbindlist = ypdb;
+ }
+
+ /* soft update, alive, less than 30 seconds old */
+ if(ypdb->dom_alive==1 && force==0 && ypdb->dom_check_t<time(NULL)+30)
+ return;
+
+ bcopy((char *)raddrp, (char *)&ypdb->dom_server_addr,
+ 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;
+
+ bzero(&ybr, 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);
+ ypdb->dom_lockfd = -1;
+ return;
+ }
+}
diff --git a/usr.sbin/yppoll/Makefile b/usr.sbin/yppoll/Makefile
new file mode 100644
index 0000000..3108b83
--- /dev/null
+++ b/usr.sbin/yppoll/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.2 1994/02/17 07:06:17 rgrimes Exp $
+
+PROG= yppoll
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/yppoll/yppoll.c b/usr.sbin/yppoll/yppoll.c
new file mode 100644
index 0000000..525e564
--- /dev/null
+++ b/usr.sbin/yppoll/yppoll.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
+ * Copyright (c) 1992/3 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. 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[] = "yppoll.c,v 1.2 1993/08/02 17:57:20 mycroft Exp";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <stdio.h>
+#include <time.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+usage()
+{
+ fprintf(stderr, "Usage:\n");
+ fprintf(stderr, "\typpoll [-h host] [-d domainname] mapname\n");
+ exit(1);
+}
+
+int
+main(argc, argv)
+char **argv;
+{
+ char *domainname;
+ char *hostname = "localhost";
+ 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;
+ case '?':
+ usage();
+ /*NOTREACHED*/
+ }
+
+ if(optind + 1 != argc )
+ usage();
+
+ inmap = argv[optind];
+
+ r = yp_order(domainname, inmap, &order);
+ 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));
+ 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("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 0000000..58bafea
--- /dev/null
+++ b/usr.sbin/ypset/Makefile
@@ -0,0 +1,7 @@
+# from: @(#)Makefile 5.8 (Berkeley) 7/28/90
+# $Id: Makefile,v 1.2 1994/02/17 07:06:19 rgrimes Exp $
+
+PROG= ypset
+NOMAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypset/ypset.c b/usr.sbin/ypset/ypset.c
new file mode 100644
index 0000000..6a25a97
--- /dev/null
+++ b/usr.sbin/ypset/ypset.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 1992/3 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. 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;
+ unsigned long server_addr;
+
+ 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( (hp = gethostbyname (server)) != NULL ) {
+ /* is this the most compatible way?? */
+ bcopy (hp->h_addr_list[0], &ypsd.ypsetdom_addr,
+ sizeof (ypsd.ypsetdom_addr));
+ } else if( (long)(server_addr = inet_addr (server)) == -1) {
+ fprintf(stderr, "can't find address for %s\n", server);
+ exit(1);
+ } else
+ bcopy (&server_addr, &ypsd.ypsetdom_addr,
+ sizeof (server_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( (sin.sin_addr.s_addr=inet_addr(optarg)) == -1) {
+ hent = gethostbyname(optarg);
+ if(hent==NULL) {
+ fprintf(stderr, "ypset: host %s unknown\n",
+ optarg);
+ exit(1);
+ }
+ bcopy(&hent->h_addr_list[0], &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/zic/Makefile b/usr.sbin/zic/Makefile
new file mode 100644
index 0000000..963a0ee
--- /dev/null
+++ b/usr.sbin/zic/Makefile
@@ -0,0 +1,5 @@
+# $Id$
+SUBDIR= zic zdump
+
+.include <bsd.subdir.mk>
+
diff --git a/usr.sbin/zic/Makefile.inc b/usr.sbin/zic/Makefile.inc
new file mode 100644
index 0000000..c961f85
--- /dev/null
+++ b/usr.sbin/zic/Makefile.inc
@@ -0,0 +1,3 @@
+# $Id$
+
+.include "${.CURDIR}/../../Makefile.inc"
diff --git a/usr.sbin/zic/README b/usr.sbin/zic/README
new file mode 100644
index 0000000..5eea1a2
--- /dev/null
+++ b/usr.sbin/zic/README
@@ -0,0 +1,72 @@
+@(#)README 7.5
+
+"What time is it?" -- Richard Deacon as The King
+"Any time you want it to be." -- Frank Baxter as The Scientist
+ (from the Bell System film on time)
+
+The 1989 update of the time zone package featured
+
+* POSIXization (including interpretation of POSIX-style TZ environment
+ variables, provided by Guy Harris),
+* ANSIfication (including versions of "mktime" and "difftime"),
+* SVIDulation (an "altzone" variable)
+* MACHination (the "gtime" function)
+* corrections to some time zone data (including corrections to the rules
+ for Great Britain and New Zealand)
+* reference data from the United States Naval Observatory for folks who
+ want to do additional time zones
+* and the 1989 data for Saudi Arabia.
+
+(Since this code will be treated as "part of the implementation" in some places
+and as "part of the application" in others, there's no good way to name
+functions, such as timegm, that are not part of the proposed ANSI C standard;
+such functions have kept their old, underscore-free names in this update.)
+
+Support for the tz_abbr variable has been eliminated from this version
+(to forestall "kitchen sink" complaints from certain quarters :-).
+
+Support for Turbo C compilation has also been eliminated; it was present to
+allow checking in an ANSI-style environment, and such checking is now done with
+gcc.
+
+And the "dysize" function has disappeared; it was present to allow compilation
+of the "date" command on old BSD systems, and a version of "date" is now
+provided in the package. The "date" command is not created when you "make all"
+since it may lack options provided by the version distributed with your
+operating system, or may not interact with the system in the same way the
+native version does.
+
+Since POSIX frowns on correct leap second handling, the default behavior of
+the "zic" command (in the absence of a "-L" option) has been changed to omit
+leap second information from its output files.
+
+Be sure to read the comments in "Makefile" and make any changes
+needed to make things right for your system.
+
+To use the new functions, use a "-lz" option when compiling or linking.
+
+Historical local time information has been included here not because it
+is particularly useful, but rather to:
+
+* give an idea of the variety of local time rules that have
+ existed in the past and thus an idea of the variety that may be
+ expected in the future;
+
+* provide a test of the generality of the local time rule description
+ system.
+
+The information in the time zone data files is by no means authoritative;
+if you know that the rules are different from those in a file, by all means
+feel free to change file (and please send the changed version to
+tz@elsie.nci.nih.gov for use in the future). Europeans take note!
+
+Thanks to these Timezone Caballeros who've made major contributions to the
+time conversion package: Keith Bostic; Bob Devine; Paul Eggert; Robert Elz;
+Guy Harris; Mark Horton; John Mackin; and Bradley White. Thanks also to
+Michael Bloom, Art Neilson, Stephen Prince, John Sovereign, and Frank Wales
+for testing work. None of them are responsible for remaining errors.
+
+Look in the ~ftp/pub directory of elsie.nci.nih.gov (128.231.16.1)
+for updated versions of these files.
+
+Please send comments or information to ado@elsie.nci.nih.gov.
diff --git a/usr.sbin/zic/Theory b/usr.sbin/zic/Theory
new file mode 100644
index 0000000..93a07c0
--- /dev/null
+++ b/usr.sbin/zic/Theory
@@ -0,0 +1,120 @@
+@(#)Theory 7.2
+
+These time and date functions are much like the System V Release 2.0 (SVR2)
+time and date functions; there are a few additions and changes to extend
+the usefulness of the SVR2 functions:
+
+* In SVR2, time display in a process is controlled by the environment
+ variable TZ, which "must be a three-letter time zone name, followed
+ by a number representing the difference between local time and
+ Greenwich Mean Time in hours, followed by an optional three-letter
+ name for a daylight time zone;" when the optional daylight time zone is
+ present, "standard U.S.A. Daylight Savings Time conversion is applied."
+ This means that SVR2 can't deal with other (for example, Australian)
+ daylight savings time rules, or situations where more than two
+ time zone abbreviations are used in an area.
+
+* In SVR2, time conversion information is compiled into each program
+ that does time conversion. This means that when time conversion
+ rules change (as in the United States in 1987), all programs that
+ do time conversion must be recompiled to ensure proper results.
+
+* In SVR2, time conversion fails for near-minimum or near-maximum
+ time_t values when doing conversions for places that don't use GMT.
+
+* In SVR2, there's no tamper-proof way for a process to learn the
+ system's best idea of local wall clock. (This is important for
+ applications that an administrator wants used only at certain times--
+ without regard to whether the user has fiddled the "TZ" environment
+ variable. While an administrator can "do everything in GMT" to get
+ around the problem, doing so is inconvenient and precludes handling
+ daylight savings time shifts--as might be required to limit phone
+ calls to off-peak hours.)
+
+* These functions can account for leap seconds, thanks to Bradley White
+ (bww@k.cs.cmu.edu).
+
+These are the changes that have been made to the SVR2 functions:
+
+* The "TZ" environment variable is used in generating the name of a file
+ from which time zone information is read (or is interpreted a la
+ POSIX); "TZ" is no longer constrained to be a three-letter time zone
+ name followed by a number of hours and an optional three-letter
+ daylight time zone name. The daylight saving time rules to be used
+ for a particular time zone are encoded in the time zone file;
+ the format of the file allows U.S., Australian, and other rules to be
+ encoded, and allows for situations where more than two time zone
+ abbreviations are used.
+
+ It was recognized that allowing the "TZ" environment variable to
+ take on values such as "US/Eastern" might cause "old" programs
+ (that expect "TZ" to have a certain form) to operate incorrectly;
+ consideration was given to using some other environment variable
+ (for example, "TIMEZONE") to hold the string used to generate the
+ time zone information file name. In the end, however, it was decided
+ to continue using "TZ": it is widely used for time zone purposes;
+ separately maintaining both "TZ" and "TIMEZONE" seemed a nuisance;
+ and systems where "new" forms of "TZ" might cause problems can simply
+ use TZ values such as "EST5EDT" which can be used both by
+ "new" programs (a la POSIX) and "old" programs (as zone names and
+ offsets).
+
+* To handle places where more than two time zone abbreviations are used,
+ the functions "localtime" and "gmtime" set tzname[tmp->tm_isdst]
+ (where "tmp" is the value the function returns) to the time zone
+ abbreviation to be used. This differs from SVR2, where the elements
+ of tzname are only changed as a result of calls to tzset.
+
+* Since the "TZ" environment variable can now be used to control time
+ conversion, the "daylight" and "timezone" variables are no longer
+ needed or supported. (You can use a compile-time option to cause
+ these variables to be defined and to be set by "tzset"; however, their
+ values will not be used by "localtime.")
+
+* The "localtime" function has been set up to deliver correct results
+ for near-minimum or near-maximum time_t values. (A comment in the
+ source code tells how to get compatibly wrong results).
+
+* A function "tzsetwall" has been added to arrange for the system's
+ best approximation to local wall clock time to be delivered by
+ subsequent calls to "localtime." Source code for portable
+ applications that "must" run on local wall clock time should call
+ "tzsetwall();" if such code is moved to "old" systems that don't provide
+ tzsetwall, you won't be able to generate an executable program.
+ (These time zone functions also arrange for local wall clock time to be
+ used if tzset is called--directly or indirectly--and there's no "TZ"
+ environment variable; portable applications should not, however, rely
+ on this behavior since it's not the way SVR2 systems behave.)
+
+Points of interest to folks with Version 7 or BSD systems:
+
+* The BSD "timezone" function is not present in this package;
+ it's impossible to reliably map timezone's arguments (a "minutes west
+ of GMT" value and a "daylight saving time in effect" flag) to a
+ time zone abbreviation, and we refuse to guess.
+ Programs that in the past used the timezone function may now examine
+ tzname[localtime(&clock)->tm_isdst] to learn the correct time
+ zone abbreviation to use. Alternatively, use localtime(&clock)->tm_zone
+ if this has been enabled.
+
+* The BSD gettimeofday function is not used in this package;
+ this lets users control the time zone used in doing time conversions.
+ Users who don't try to control things (that is, users who do not set
+ the environment variable TZ) get the time conversion specified in the
+ file "/etc/zoneinfo/localtime"; see the time zone compiler writeup for
+ information on how to initialize this file.
+
+The functions that are conditionally compiled if STD_INSPIRED is defined should,
+at this point, be looked on primarily as food for thought. They are not in
+any sense "standard compatible"--some are not, in fact, specified in *any*
+standard. They do, however, represent responses of various authors to
+standardization proposals.
+
+Other time conversion proposals, in particular the one developed by folks at
+Hewlett Packard, offer a wider selection of functions that provide capabilities
+beyond those provided here. The absence of such functions from this package
+is not meant to discourage the development, standardization, or use of such
+functions. Rather, their absence reflects the decision to make this package
+close to SVR2 (with the exceptions outlined above) to ensure its broad
+acceptability. If more powerful time conversion functions can be standardized,
+so much the better.
diff --git a/usr.sbin/zic/ialloc.c b/usr.sbin/zic/ialloc.c
new file mode 100644
index 0000000..7dc2f2b
--- /dev/null
+++ b/usr.sbin/zic/ialloc.c
@@ -0,0 +1,103 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)ialloc.c 8.21";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+#ifdef MAL
+#define NULLMAL(x) ((x) == NULL || (x) == MAL)
+#endif /* defined MAL */
+#ifndef MAL
+#define NULLMAL(x) ((x) == NULL)
+#endif /* !defined MAL */
+
+#define nonzero(n) (((n) == 0) ? 1 : (n))
+
+char * icalloc P((int nelem, int elsize));
+char * icatalloc P((char * old, const char * new));
+char * icpyalloc P((const char * string));
+char * imalloc P((int n));
+char * irealloc P((char * pointer, int size));
+void ifree P((char * pointer));
+
+char *
+imalloc(n)
+const int n;
+{
+#ifdef MAL
+ register char * result;
+
+ result = malloc((alloc_size_t) nonzero(n));
+ return NULLMAL(result) ? NULL : result;
+#endif /* defined MAL */
+#ifndef MAL
+ return malloc((alloc_size_t) nonzero(n));
+#endif /* !defined MAL */
+}
+
+char *
+icalloc(nelem, elsize)
+int nelem;
+int elsize;
+{
+ if (nelem == 0 || elsize == 0)
+ nelem = elsize = 1;
+ return calloc((alloc_size_t) nelem, (alloc_size_t) elsize);
+}
+
+char *
+irealloc(pointer, size)
+char * const pointer;
+const int size;
+{
+ if (NULLMAL(pointer))
+ return imalloc(size);
+ return realloc((genericptr_t) pointer, (alloc_size_t) nonzero(size));
+}
+
+char *
+icatalloc(old, new)
+char * const old;
+const char * const new;
+{
+ register char * result;
+ register int oldsize, newsize;
+
+ newsize = NULLMAL(new) ? 0 : strlen(new);
+ if (NULLMAL(old))
+ oldsize = 0;
+ else if (newsize == 0)
+ return old;
+ else oldsize = strlen(old);
+ if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
+ if (!NULLMAL(new))
+ (void) strcpy(result + oldsize, new);
+ return result;
+}
+
+char *
+icpyalloc(string)
+const char * const string;
+{
+ return icatalloc((char *) NULL, string);
+}
+
+void
+ifree(p)
+char * const p;
+{
+ if (!NULLMAL(p))
+ (void) free(p);
+}
+
+void
+icfree(p)
+char * const p;
+{
+ if (!NULLMAL(p))
+ (void) free(p);
+}
diff --git a/usr.sbin/zic/scheck.c b/usr.sbin/zic/scheck.c
new file mode 100644
index 0000000..4d9616d
--- /dev/null
+++ b/usr.sbin/zic/scheck.c
@@ -0,0 +1,62 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)scheck.c 8.11";
+#endif /* !defined lint */
+#endif /* !defined NOID */
+
+/*LINTLIBRARY*/
+
+#include "private.h"
+
+extern char * imalloc P((int n));
+extern void ifree P((char * p));
+
+char *
+scheck(string, format)
+const char * const string;
+const char * const format;
+{
+ register char * fbuf;
+ register const char * fp;
+ register char * tp;
+ register int c;
+ register char * result;
+ char dummy;
+ static char nada[1];
+
+ result = nada;
+ if (string == NULL || format == NULL)
+ return result;
+ fbuf = imalloc(2 * strlen(format) + 4);
+ if (fbuf == NULL)
+ return result;
+ fp = format;
+ tp = fbuf;
+ while ((*tp++ = c = *fp++) != '\0') {
+ if (c != '%')
+ continue;
+ if (*fp == '%') {
+ *tp++ = *fp++;
+ continue;
+ }
+ *tp++ = '*';
+ if (*fp == '*')
+ ++fp;
+ while (isascii(*fp) && isdigit(*fp))
+ *tp++ = *fp++;
+ if (*fp == 'l' || *fp == 'h')
+ *tp++ = *fp++;
+ else if (*fp == '[')
+ do *tp++ = *fp++;
+ while (*fp != '\0' && *fp != ']');
+ if ((*tp++ = *fp++) == '\0')
+ break;
+ }
+ *(tp - 1) = '%';
+ *tp++ = 'c';
+ *tp = '\0';
+ if (sscanf(string, fbuf, &dummy) != 1)
+ result = (char *) format;
+ ifree(fbuf);
+ return result;
+}
diff --git a/usr.sbin/zic/zdump.8 b/usr.sbin/zic/zdump.8
new file mode 100644
index 0000000..23f4946
--- /dev/null
+++ b/usr.sbin/zic/zdump.8
@@ -0,0 +1,40 @@
+.TH ZDUMP 8
+.SH NAME
+zdump \- time zone dumper
+.SH SYNOPSIS
+.B zdump
+[
+.B \-v
+] [
+.B \-c
+cutoffyear ] [ zonename ... ]
+.SH DESCRIPTION
+.I Zdump
+prints the current time in each
+.I zonename
+named on the command line.
+.PP
+These options are available:
+.TP
+.B \-v
+For each
+.I zonename
+on the command line,
+print the current time,
+the time at the lowest possible time value,
+the time one day after the lowest possible time value,
+the times both one second before and exactly at
+each detected time discontinuity,
+the time at one day less than the highest possible time value,
+and the time at the highest possible time value,
+Each line ends with
+.B isdst=1
+if the given time is Daylight Saving Time or
+.B isdst=0
+otherwise.
+.TP
+.BI "\-c " cutoffyear
+Cut off the verbose output near the start of the given year.
+.SH "SEE ALSO"
+newctime(3), tzfile(5), zic(8)
+.\" @(#)zdump.8 7.2
diff --git a/usr.sbin/zic/zdump.c b/usr.sbin/zic/zdump.c
new file mode 100644
index 0000000..1e44d4a
--- /dev/null
+++ b/usr.sbin/zic/zdump.c
@@ -0,0 +1,307 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)zdump.c 7.10";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+/*
+** This code has been made independent of the rest of the time
+** conversion package to increase confidence in the verification it provides.
+** You can use this code to help in verifying other implementations.
+*/
+
+#include "stdio.h" /* for stdout, stderr */
+#include "string.h" /* for strcpy */
+#include "sys/types.h" /* for time_t */
+#include "time.h" /* for struct tm */
+
+#ifndef MAX_STRING_LENGTH
+#define MAX_STRING_LENGTH 1024
+#endif /* !defined MAX_STRING_LENGTH */
+
+#ifndef TRUE
+#define TRUE 1
+#endif /* !defined TRUE */
+
+#ifndef FALSE
+#define FALSE 0
+#endif /* !defined FALSE */
+
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS 0
+#endif /* !defined EXIT_SUCCESS */
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif /* !defined EXIT_FAILURE */
+
+#ifndef SECSPERMIN
+#define SECSPERMIN 60
+#endif /* !defined SECSPERMIN */
+
+#ifndef MINSPERHOUR
+#define MINSPERHOUR 60
+#endif /* !defined MINSPERHOUR */
+
+#ifndef SECSPERHOUR
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#endif /* !defined SECSPERHOUR */
+
+#ifndef HOURSPERDAY
+#define HOURSPERDAY 24
+#endif /* !defined HOURSPERDAY */
+
+#ifndef EPOCH_YEAR
+#define EPOCH_YEAR 1970
+#endif /* !defined EPOCH_YEAR */
+
+#ifndef TM_YEAR_BASE
+#define TM_YEAR_BASE 1900
+#endif /* !defined TM_YEAR_BASE */
+
+#ifndef DAYSPERNYEAR
+#define DAYSPERNYEAR 365
+#endif /* !defined DAYSPERNYEAR */
+
+#ifndef isleap
+#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
+#endif /* !defined isleap */
+
+extern char ** environ;
+extern int getopt();
+extern char * optarg;
+extern int optind;
+extern time_t time();
+extern char * tzname[2];
+extern void tzset();
+
+#ifdef USG
+extern void exit();
+extern void perror();
+#endif /* defined USG */
+
+static char * abbr();
+static long delta();
+static time_t hunt();
+static int longest;
+static char * progname;
+static void show();
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i, c;
+ register int vflag;
+ register char * cutoff;
+ register int cutyear;
+ register long cuttime;
+ time_t now;
+ time_t t, newt;
+ time_t hibit;
+ struct tm tm, newtm;
+
+ progname = argv[0];
+ vflag = 0;
+ cutoff = NULL;
+ while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
+ if (c == 'v')
+ vflag = 1;
+ else cutoff = optarg;
+ if (c != EOF ||
+ (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
+ (void) fprintf(stderr,
+"%s: usage is %s [ -v ] [ -c cutoff ] zonename ...\n",
+ argv[0], argv[0]);
+ (void) exit(EXIT_FAILURE);
+ }
+ if (cutoff != NULL) {
+ int y;
+
+ cutyear = atoi(cutoff);
+ cuttime = 0;
+ for (y = EPOCH_YEAR; y < cutyear; ++y)
+ cuttime += DAYSPERNYEAR + isleap(y);
+ cuttime *= SECSPERHOUR * HOURSPERDAY;
+ }
+ (void) time(&now);
+ longest = 0;
+ for (i = optind; i < argc; ++i)
+ if (strlen(argv[i]) > longest)
+ longest = strlen(argv[i]);
+ for (hibit = 1; (hibit << 1) != 0; hibit <<= 1)
+ continue;
+ for (i = optind; i < argc; ++i) {
+ register char ** saveenv;
+ static char buf[MAX_STRING_LENGTH];
+ char * fakeenv[2];
+
+ if (strlen(argv[i]) + 4 > sizeof buf) {
+ (void) fflush(stdout);
+ (void) fprintf(stderr, "%s: argument too long -- %s\n",
+ progname, argv[i]);
+ (void) exit(EXIT_FAILURE);
+ }
+ (void) strcpy(buf, "TZ=");
+ (void) strcat(buf, argv[i]);
+ fakeenv[0] = buf;
+ fakeenv[1] = NULL;
+ saveenv = environ;
+ environ = fakeenv;
+ (void) tzset();
+ environ = saveenv;
+ show(argv[i], now, FALSE);
+ if (!vflag)
+ continue;
+ /*
+ ** Get lowest value of t.
+ */
+ t = hibit;
+ if (t > 0) /* time_t is unsigned */
+ t = 0;
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ tm = *localtime(&t);
+ (void) strncpy(buf, abbr(&tm), (sizeof buf) - 1);
+ for ( ; ; ) {
+ if (cutoff != NULL && t >= cuttime)
+ break;
+ newt = t + SECSPERHOUR * 12;
+ if (cutoff != NULL && newt >= cuttime)
+ break;
+ if (newt <= t)
+ break;
+ newtm = *localtime(&newt);
+ if (delta(&newtm, &tm) != (newt - t) ||
+ newtm.tm_isdst != tm.tm_isdst ||
+ strcmp(abbr(&newtm), buf) != 0) {
+ newt = hunt(argv[i], t, newt);
+ newtm = *localtime(&newt);
+ (void) strncpy(buf, abbr(&newtm),
+ (sizeof buf) - 1);
+ }
+ t = newt;
+ tm = newtm;
+ }
+ /*
+ ** Get highest value of t.
+ */
+ t = ~((time_t) 0);
+ if (t < 0) /* time_t is signed */
+ t &= ~hibit;
+ t -= SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ t += SECSPERHOUR * HOURSPERDAY;
+ show(argv[i], t, TRUE);
+ }
+ if (fflush(stdout) || ferror(stdout)) {
+ (void) fprintf(stderr, "%s: Error writing standard output ",
+ argv[0]);
+ (void) perror("standard output");
+ (void) exit(EXIT_FAILURE);
+ }
+ exit(EXIT_SUCCESS);
+
+ /* gcc -Wall pacifier */
+ for ( ; ; )
+ continue;
+}
+
+static time_t
+hunt(name, lot, hit)
+char * name;
+time_t lot;
+time_t hit;
+{
+ time_t t;
+ struct tm lotm;
+ struct tm tm;
+ static char loab[MAX_STRING_LENGTH];
+
+ lotm = *localtime(&lot);
+ (void) strncpy(loab, abbr(&lotm), (sizeof loab) - 1);
+ while ((hit - lot) >= 2) {
+ t = lot / 2 + hit / 2;
+ if (t <= lot)
+ ++t;
+ else if (t >= hit)
+ --t;
+ tm = *localtime(&t);
+ if (delta(&tm, &lotm) == (t - lot) &&
+ tm.tm_isdst == lotm.tm_isdst &&
+ strcmp(abbr(&tm), loab) == 0) {
+ lot = t;
+ lotm = tm;
+ } else hit = t;
+ }
+ show(name, lot, TRUE);
+ show(name, hit, TRUE);
+ return hit;
+}
+
+/*
+** Thanks to Paul Eggert (eggert@twinsun.com) for logic used in delta.
+*/
+
+static long
+delta(newp, oldp)
+struct tm * newp;
+struct tm * oldp;
+{
+ long result;
+ int tmy;
+
+ if (newp->tm_year < oldp->tm_year)
+ return -delta(oldp, newp);
+ result = 0;
+ for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
+ result += DAYSPERNYEAR + isleap(tmy + TM_YEAR_BASE);
+ result += newp->tm_yday - oldp->tm_yday;
+ result *= HOURSPERDAY;
+ result += newp->tm_hour - oldp->tm_hour;
+ result *= MINSPERHOUR;
+ result += newp->tm_min - oldp->tm_min;
+ result *= SECSPERMIN;
+ result += newp->tm_sec - oldp->tm_sec;
+ return result;
+}
+
+static void
+show(zone, t, v)
+char * zone;
+time_t t;
+int v;
+{
+ struct tm * tmp;
+ extern struct tm * localtime();
+
+ (void) printf("%-*s ", longest, zone);
+ if (v)
+ (void) printf("%.24s GMT = ", asctime(gmtime(&t)));
+ tmp = localtime(&t);
+ (void) printf("%.24s", asctime(tmp));
+ if (*abbr(tmp) != '\0')
+ (void) printf(" %s", abbr(tmp));
+ if (v) {
+ (void) printf(" isdst=%d", tmp->tm_isdst);
+#ifdef TM_GMTOFF
+ (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
+#endif /* defined TM_GMTOFF */
+ }
+ (void) printf("\n");
+}
+
+static char *
+abbr(tmp)
+struct tm * tmp;
+{
+ register char * result;
+ static char nada[1];
+
+ if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
+ return nada;
+ result = tzname[tmp->tm_isdst];
+ return (result == NULL) ? nada : result;
+}
diff --git a/usr.sbin/zic/zdump/Makefile b/usr.sbin/zic/zdump/Makefile
new file mode 100644
index 0000000..46af3ca
--- /dev/null
+++ b/usr.sbin/zic/zdump/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+
+.PATH: ${.CURDIR}/..
+
+PROG= zdump
+
+SRCS= zdump.c ialloc.c scheck.c
+MAN8= ${.CURDIR}/../zdump.8
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/zic/zic.8 b/usr.sbin/zic/zic.8
new file mode 100644
index 0000000..6972d0e
--- /dev/null
+++ b/usr.sbin/zic/zic.8
@@ -0,0 +1,412 @@
+.TH ZIC 8
+.SH NAME
+zic \- time zone compiler
+.SH SYNOPSIS
+.B zic
+[
+.B \-v
+] [
+.B \-d
+.I directory
+] [
+.B \-l
+.I localtime
+] [
+.B \-p
+.I posixrules
+] [
+.B \-L
+.I leapsecondfilename
+] [
+.B \-s
+] [
+.B \-y
+.I command
+] [
+.I filename
+\&... ]
+.SH DESCRIPTION
+.if t .ds lq ``
+.if t .ds rq ''
+.if n .ds lq \&"\"
+.if n .ds rq \&"\"
+.de q
+\\$3\*(lq\\$1\*(rq\\$2
+..
+.I Zic
+reads text from the file(s) named on the command line
+and creates the time conversion information files specified in this input.
+If a
+.I filename
+is
+.BR \- ,
+the standard input is read.
+.PP
+These options are available:
+.TP
+.BI "\-d " directory
+Create time conversion information files in the named directory rather than
+in the standard directory named below.
+.TP
+.BI "\-l " timezone
+Use the given time zone as local time.
+.I Zic
+will act as if the input contained a link line of the form
+.sp
+.ti +.5i
+Link \fItimezone\fP localtime
+.TP
+.BI "\-p " timezone
+Use the given time zone's rules when handling POSIX-format
+time zone environment variables.
+.I Zic
+will act as if the input contained a link line of the form
+.sp
+.ti +.5i
+Link \fItimezone\fP posixrules
+.TP
+.BI "\-L " leapsecondfilename
+Read leap second information from the file with the given name.
+If this option is not used,
+no leap second information appears in output files.
+.TP
+.B \-v
+Complain if a year that appears in a data file is outside the range
+of years representable by
+.IR time (2)
+values.
+.TP
+.B \-s
+Limit time values stored in output files to values that are the same
+whether they're taken to be signed or unsigned.
+You can use this option to generate SVVS-compatible files.
+.TP
+.BI "\-y " command
+Use the given
+.I command
+rather than
+.B yearistype
+when checking year types (see below).
+.PP
+Input lines are made up of fields.
+Fields are separated from one another by any number of white space characters.
+Leading and trailing white space on input lines is ignored.
+An unquoted sharp character (#) in the input introduces a comment which extends
+to the end of the line the sharp character appears on.
+White space characters and sharp characters may be enclosed in double quotes
+(") if they're to be used as part of a field.
+Any line that is blank (after comment stripping) is ignored.
+Non-blank lines are expected to be of one of three types:
+rule lines, zone lines, and link lines.
+.PP
+A rule line has the form
+.nf
+.ti +.5i
+.ta \w'Rule\0\0'u +\w'NAME\0\0'u +\w'FROM\0\0'u +\w'1973\0\0'u +\w'TYPE\0\0'u +\w'Apr\0\0'u +\w'lastSun\0\0'u +\w'2:00\0\0'u +\w'SAVE\0\0'u
+.sp
+Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
+.sp
+For example:
+.ti +.5i
+.sp
+Rule US 1967 1973 \- Apr lastSun 2:00 1:00 D
+.sp
+.fi
+The fields that make up a rule line are:
+.TP "\w'LETTER/S'u"
+.B NAME
+Gives the (arbitrary) name of the set of rules this rule is part of.
+.TP
+.B FROM
+Gives the first year in which the rule applies.
+Any integer year can be supplied; the Gregorian calendar is assumed.
+The word
+.B minimum
+(or an abbreviation) means the minimum year representable as an integer.
+The word
+.B maximum
+(or an abbreviation) means the maximum year representable as an integer.
+Rules can describe times that are not representable as time values,
+with the unrepresentable times ignored; this allows rules to be portable
+among hosts with differing time value types.
+.TP
+.B TO
+Gives the final year in which the rule applies.
+In addition to
+.B minimum
+and
+.B maximum
+(as above),
+the word
+.B only
+(or an abbreviation)
+may be used to repeat the value of the
+.B FROM
+field.
+.TP
+.B TYPE
+Gives the type of year in which the rule applies.
+If
+.B TYPE
+is
+.B \-
+then the rule applies in all years between
+.B FROM
+and
+.B TO
+inclusive;
+if
+.B TYPE
+is
+.BR uspres ,
+the rule applies in U.S. Presidential election years;
+if
+.B TYPE
+is
+.BR nonpres ,
+the rule applies in years other than U.S. Presidential election years.
+If
+.B TYPE
+is something else, then
+.I zic
+executes the command
+.ti +.5i
+\fByearistype\fP \fIyear\fP \fItype\fP
+.br
+to check the type of a year:
+an exit status of zero is taken to mean that the year is of the given type;
+an exit status of one is taken to mean that the year is not of the given type.
+.TP
+.B IN
+Names the month in which the rule takes effect.
+Month names may be abbreviated.
+.TP
+.B ON
+Gives the day on which the rule takes effect.
+Recognized forms include:
+.nf
+.in +.5i
+.sp
+.ta \w'Sun<=25\0\0'u
+5 the fifth of the month
+lastSun the last Sunday in the month
+lastMon the last Monday in the month
+Sun>=8 first Sunday on or after the eighth
+Sun<=25 last Sunday on or before the 25th
+.fi
+.in -.5i
+.sp
+Names of days of the week may be abbreviated or spelled out in full.
+Note that there must be no spaces within the
+.B ON
+field.
+.TP
+.B AT
+Gives the time of day at which the rule takes effect.
+Recognized forms include:
+.nf
+.in +.5i
+.sp
+.ta \w'1:28:13\0\0'u
+2 time in hours
+2:00 time in hours and minutes
+15:00 24-hour format time (for times after noon)
+1:28:14 time in hours, minutes, and seconds
+.fi
+.in -.5i
+.sp
+Any of these forms may be followed by the letter
+.B w
+if the given time is local
+.q "wall clock"
+time or
+.B s
+if the given time is local
+.q standard
+time; in the absence of
+.B w
+or
+.BR s ,
+wall clock time is assumed.
+.TP
+.B SAVE
+Gives the amount of time to be added to local standard time when the rule is in
+effect.
+This field has the same format as the
+.B AT
+field
+(although, of course, the
+.B w
+and
+.B s
+suffixes are not used).
+.TP
+.B LETTER/S
+Gives the
+.q "variable part"
+(for example, the
+.q S
+or
+.q D
+in
+.q EST
+or
+.q EDT )
+of time zone abbreviations to be used when this rule is in effect.
+If this field is
+.BR \- ,
+the variable part is null.
+.PP
+A zone line has the form
+.sp
+.nf
+.ti +.5i
+.ta \w'Zone\0\0'u +\w'Australia/Adelaide\0\0'u +\w'GMTOFF\0\0'u +\w'RULES/SAVE\0\0'u +\w'FORMAT\0\0'u
+Zone NAME GMTOFF RULES/SAVE FORMAT [UNTIL]
+.sp
+For example:
+.sp
+.ti +.5i
+Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
+.sp
+.fi
+The fields that make up a zone line are:
+.TP "\w'GMTOFF'u"
+.B NAME
+The name of the time zone.
+This is the name used in creating the time conversion information file for the
+zone.
+.TP
+.B GMTOFF
+The amount of time to add to GMT to get standard time in this zone.
+This field has the same format as the
+.B AT
+and
+.B SAVE
+fields of rule lines;
+begin the field with a minus sign if time must be subtracted from GMT.
+.TP
+.B RULES/SAVE
+The name of the rule(s) that apply in the time zone or,
+alternately, an amount of time to add to local standard time.
+If this field is
+.B \-
+then standard time always applies in the time zone.
+.TP
+.B FORMAT
+The format for time zone abbreviations in this time zone.
+The pair of characters
+.B %s
+is used to show where the
+.q "variable part"
+of the time zone abbreviation goes.
+.TP
+.B UNTIL
+The time at which the GMT offset or the rule(s) change for a location.
+It is specified as a year, a month, a day, and a time of day.
+If this is specified,
+the time zone information is generated from the given GMT offset
+and rule change until the time specified.
+.IP
+The next line must be a
+.q continuation
+line; this has the same form as a zone line except that the
+string
+.q Zone
+and the name are omitted, as the continuation line will
+place information starting at the time specified as the
+.B UNTIL
+field in the previous line in the file used by the previous line.
+Continuation lines may contain an
+.B UNTIL
+field, just as zone lines do, indicating that the next line is a further
+continuation.
+.PP
+A link line has the form
+.sp
+.nf
+.ti +.5i
+.if t .ta \w'Link\0\0'u +\w'LINK-FROM\0\0'u
+.if n .ta \w'Link\0\0'u +\w'US/Eastern\0\0'u
+Link LINK-FROM LINK-TO
+.sp
+For example:
+.sp
+.ti +.5i
+Link US/Eastern EST5EDT
+.sp
+.fi
+The
+.B LINK-FROM
+field should appear as the
+.B NAME
+field in some zone line;
+the
+.B LINK-TO
+field is used as an alternate name for that zone.
+.PP
+Except for continuation lines,
+lines may appear in any order in the input.
+.PP
+Lines in the file that describes leap seconds have the following form:
+.nf
+.ti +.5i
+.ta \w'Leap\0\0'u +\w'YEAR\0\0'u +\w'MONTH\0\0'u +\w'DAY\0\0'u +\w'HH:MM:SS\0\0'u +\w'CORR\0\0'u
+.sp
+Leap YEAR MONTH DAY HH:MM:SS CORR R/S
+.sp
+For example:
+.ti +.5i
+.sp
+Leap 1974 Dec 31 23:59:60 + S
+.sp
+.fi
+The
+.BR YEAR ,
+.BR MONTH ,
+.BR DAY ,
+and
+.B HH:MM:SS
+fields tell when the leap second happened.
+The
+.B CORR
+field
+should be
+.q +
+if a second was added
+or
+.q -
+if a second was skipped.
+.\" There's no need to document the following, since it's impossible for more
+.\" than one leap second to be inserted or deleted at a time.
+.\" The C Standard is in error in suggesting the possibility.
+.\" See Terry J Quinn, The BIPM and the accurate measure of time,
+.\" Proc IEEE 79, 7 (July 1991), 894-905.
+.\" or
+.\" .q ++
+.\" if two seconds were added
+.\" or
+.\" .q --
+.\" if two seconds were skipped.
+The
+.B R/S
+field
+should be (an abbreviation of)
+.q Stationary
+if the leap second time given by the other fields should be interpreted as GMT
+or
+(an abbreviation of)
+.q Rolling
+if the leap second time given by the other fields should be interpreted as
+local wall clock time.
+.SH NOTE
+For areas with more than two types of local time,
+you may need to use local standard time in the
+.B AT
+field of the earliest transition time's rule to ensure that
+the earliest transition time recorded in the compiled file is correct.
+.SH FILE
+/usr/local/etc/zoneinfo standard directory used for created files
+.SH "SEE ALSO"
+newctime(3), tzfile(5), zdump(8)
+.\" @(#)zic.8 7.7
diff --git a/usr.sbin/zic/zic.c b/usr.sbin/zic/zic.c
new file mode 100644
index 0000000..82539fa
--- /dev/null
+++ b/usr.sbin/zic/zic.c
@@ -0,0 +1,1939 @@
+#ifndef lint
+#ifndef NOID
+static char elsieid[] = "@(#)zic.c 7.22";
+#endif /* !defined NOID */
+#endif /* !defined lint */
+
+#include "private.h"
+#include "tzfile.h"
+
+struct rule {
+ const char * r_filename;
+ int r_linenum;
+ const char * r_name;
+
+ int r_loyear; /* for example, 1986 */
+ int r_hiyear; /* for example, 1986 */
+ const char * r_yrtype;
+
+ int r_month; /* 0..11 */
+
+ int r_dycode; /* see below */
+ int r_dayofmonth;
+ int r_wday;
+
+ long r_tod; /* time from midnight */
+ int r_todisstd; /* above is standard time if TRUE */
+ /* or wall clock time if FALSE */
+ long r_stdoff; /* offset from standard time */
+ const char * r_abbrvar; /* variable part of abbreviation */
+
+ int r_todo; /* a rule to do (used in outzone) */
+ time_t r_temp; /* used in outzone */
+};
+
+/*
+** r_dycode r_dayofmonth r_wday
+*/
+
+#define DC_DOM 0 /* 1..31 */ /* unused */
+#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
+#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
+
+struct zone {
+ const char * z_filename;
+ int z_linenum;
+
+ const char * z_name;
+ long z_gmtoff;
+ const char * z_rule;
+ const char * z_format;
+
+ long z_stdoff;
+
+ struct rule * z_rules;
+ int z_nrules;
+
+ struct rule z_untilrule;
+ time_t z_untiltime;
+};
+
+extern int emkdir P((const char * name, int mode));
+extern int getopt P((int argc, char * argv[], const char * options));
+extern char * icatalloc P((char * old, const char * new));
+extern char * icpyalloc P((const char * string));
+extern void ifree P((char * p));
+extern char * imalloc P((int n));
+extern char * irealloc P((char * old, int n));
+extern int link P((const char * fromname, const char * toname));
+extern char * optarg;
+extern int optind;
+extern char * scheck P((const char * string, const char * format));
+
+static void addtt P((time_t starttime, int type));
+static int addtype P((long gmtoff, const char * abbr, int isdst,
+ int ttisstd));
+static void leapadd P((time_t t, int positive, int rolling, int count));
+static void adjleap P((void));
+static void associate P((void));
+static int ciequal P((const char * ap, const char * bp));
+static void convert P((long val, char * buf));
+static void dolink P((const char * fromfile, const char * tofile));
+static void eat P((const char * name, int num));
+static void eats P((const char * name, int num,
+ const char * rname, int rnum));
+static long eitol P((int i));
+static void error P((const char * message));
+static char ** getfields P((char * buf));
+static long gethms P((const char * string, const char * errstrng,
+ int signable));
+static void infile P((const char * filename));
+static void inleap P((char ** fields, int nfields));
+static void inlink P((char ** fields, int nfields));
+static void inrule P((char ** fields, int nfields));
+static int inzcont P((char ** fields, int nfields));
+static int inzone P((char ** fields, int nfields));
+static int inzsub P((char ** fields, int nfields, int iscont));
+static int itsabbr P((const char * abbr, const char * word));
+static int itsdir P((const char * name));
+static int lowerit P((int c));
+static char * memcheck P((char * tocheck));
+static int mkdirs P((char * filename));
+static void newabbr P((const char * abbr));
+static long oadd P((long t1, long t2));
+static void outzone P((const struct zone * zp, int ntzones));
+static void puttzcode P((long code, FILE * fp));
+static int rcomp P((const genericptr_t leftp, const genericptr_t rightp));
+static time_t rpytime P((const struct rule * rp, int wantedy));
+static void rulesub P((struct rule * rp,
+ char * loyearp, char * hiyearp,
+ char * typep, char * monthp,
+ char * dayp, char * timep));
+static void setboundaries P((void));
+static time_t tadd P((time_t t1, long t2));
+static void usage P((void));
+static void writezone P((const char * name));
+static int yearistype P((int year, const char * type));
+
+static int charcnt;
+static int errors;
+static const char * filename;
+static int leapcnt;
+static int linenum;
+static int max_int;
+static time_t max_time;
+static int max_year;
+static int min_int;
+static time_t min_time;
+static int min_year;
+static int noise;
+static const char * rfilename;
+static int rlinenum;
+static const char * progname;
+static int timecnt;
+static int typecnt;
+static int tt_signed;
+
+/*
+** Line codes.
+*/
+
+#define LC_RULE 0
+#define LC_ZONE 1
+#define LC_LINK 2
+#define LC_LEAP 3
+
+/*
+** Which fields are which on a Zone line.
+*/
+
+#define ZF_NAME 1
+#define ZF_GMTOFF 2
+#define ZF_RULE 3
+#define ZF_FORMAT 4
+#define ZF_TILYEAR 5
+#define ZF_TILMONTH 6
+#define ZF_TILDAY 7
+#define ZF_TILTIME 8
+#define ZONE_MINFIELDS 5
+#define ZONE_MAXFIELDS 9
+
+/*
+** Which fields are which on a Zone continuation line.
+*/
+
+#define ZFC_GMTOFF 0
+#define ZFC_RULE 1
+#define ZFC_FORMAT 2
+#define ZFC_TILYEAR 3
+#define ZFC_TILMONTH 4
+#define ZFC_TILDAY 5
+#define ZFC_TILTIME 6
+#define ZONEC_MINFIELDS 3
+#define ZONEC_MAXFIELDS 7
+
+/*
+** Which files are which on a Rule line.
+*/
+
+#define RF_NAME 1
+#define RF_LOYEAR 2
+#define RF_HIYEAR 3
+#define RF_COMMAND 4
+#define RF_MONTH 5
+#define RF_DAY 6
+#define RF_TOD 7
+#define RF_STDOFF 8
+#define RF_ABBRVAR 9
+#define RULE_FIELDS 10
+
+/*
+** Which fields are which on a Link line.
+*/
+
+#define LF_FROM 1
+#define LF_TO 2
+#define LINK_FIELDS 3
+
+/*
+** Which fields are which on a Leap line.
+*/
+
+#define LP_YEAR 1
+#define LP_MONTH 2
+#define LP_DAY 3
+#define LP_TIME 4
+#define LP_CORR 5
+#define LP_ROLL 6
+#define LEAP_FIELDS 7
+
+/*
+** Year synonyms.
+*/
+
+#define YR_MINIMUM 0
+#define YR_MAXIMUM 1
+#define YR_ONLY 2
+
+static struct rule * rules;
+static int nrules; /* number of rules */
+
+static struct zone * zones;
+static int nzones; /* number of zones */
+
+struct link {
+ const char * l_filename;
+ int l_linenum;
+ const char * l_from;
+ const char * l_to;
+};
+
+static struct link * links;
+static int nlinks;
+
+struct lookup {
+ const char * l_word;
+ const int l_value;
+};
+
+static struct lookup const * byword P((const char * string,
+ const struct lookup * lp));
+
+static struct lookup const line_codes[] = {
+ { "Rule", LC_RULE },
+ { "Zone", LC_ZONE },
+ { "Link", LC_LINK },
+ { "Leap", LC_LEAP },
+ { NULL, 0}
+};
+
+static struct lookup const mon_names[] = {
+ { "January", TM_JANUARY },
+ { "February", TM_FEBRUARY },
+ { "March", TM_MARCH },
+ { "April", TM_APRIL },
+ { "May", TM_MAY },
+ { "June", TM_JUNE },
+ { "July", TM_JULY },
+ { "August", TM_AUGUST },
+ { "September", TM_SEPTEMBER },
+ { "October", TM_OCTOBER },
+ { "November", TM_NOVEMBER },
+ { "December", TM_DECEMBER },
+ { NULL, 0 }
+};
+
+static struct lookup const wday_names[] = {
+ { "Sunday", TM_SUNDAY },
+ { "Monday", TM_MONDAY },
+ { "Tuesday", TM_TUESDAY },
+ { "Wednesday", TM_WEDNESDAY },
+ { "Thursday", TM_THURSDAY },
+ { "Friday", TM_FRIDAY },
+ { "Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const lasts[] = {
+ { "last-Sunday", TM_SUNDAY },
+ { "last-Monday", TM_MONDAY },
+ { "last-Tuesday", TM_TUESDAY },
+ { "last-Wednesday", TM_WEDNESDAY },
+ { "last-Thursday", TM_THURSDAY },
+ { "last-Friday", TM_FRIDAY },
+ { "last-Saturday", TM_SATURDAY },
+ { NULL, 0 }
+};
+
+static struct lookup const begin_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { NULL, 0 }
+};
+
+static struct lookup const end_years[] = {
+ { "minimum", YR_MINIMUM },
+ { "maximum", YR_MAXIMUM },
+ { "only", YR_ONLY },
+ { NULL, 0 }
+};
+
+static struct lookup const leap_types[] = {
+ { "Rolling", TRUE },
+ { "Stationary", FALSE },
+ { NULL, 0 }
+};
+
+static const int len_months[2][MONSPERYEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
+
+static const int len_years[2] = {
+ DAYSPERNYEAR, DAYSPERLYEAR
+};
+
+static time_t ats[TZ_MAX_TIMES];
+static unsigned char types[TZ_MAX_TIMES];
+static long gmtoffs[TZ_MAX_TYPES];
+static char isdsts[TZ_MAX_TYPES];
+static unsigned char abbrinds[TZ_MAX_TYPES];
+static char ttisstds[TZ_MAX_TYPES];
+static char chars[TZ_MAX_CHARS];
+static time_t trans[TZ_MAX_LEAPS];
+static long corr[TZ_MAX_LEAPS];
+static char roll[TZ_MAX_LEAPS];
+
+/*
+** Memory allocation.
+*/
+
+static char *
+memcheck(ptr)
+char * const ptr;
+{
+ if (ptr == NULL) {
+ (void) perror(progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ return ptr;
+}
+
+#define emalloc(size) memcheck(imalloc(size))
+#define erealloc(ptr, size) memcheck(irealloc(ptr, size))
+#define ecpyalloc(ptr) memcheck(icpyalloc(ptr))
+#define ecatalloc(oldp, newp) memcheck(icatalloc(oldp, newp))
+
+/*
+** Error handling.
+*/
+
+static void
+eats(name, num, rname, rnum)
+const char * const name;
+const int num;
+const char * const rname;
+const int rnum;
+{
+ filename = name;
+ linenum = num;
+ rfilename = rname;
+ rlinenum = rnum;
+}
+
+static void
+eat(name, num)
+const char * const name;
+const int num;
+{
+ eats(name, num, (char *) NULL, -1);
+}
+
+static void
+error(string)
+const char * const string;
+{
+ /*
+ ** Match the format of "cc" to allow sh users to
+ ** zic ... 2>&1 | error -t "*" -v
+ ** on BSD systems.
+ */
+ (void) fprintf(stderr, "\"%s\", line %d: %s",
+ filename, linenum, string);
+ if (rfilename != NULL)
+ (void) fprintf(stderr, " (rule from \"%s\", line %d)",
+ rfilename, rlinenum);
+ (void) fprintf(stderr, "\n");
+ ++errors;
+}
+
+static void
+usage()
+{
+ (void) fprintf(stderr,
+"%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -p posixrules ] [ -d directory ] \n\
+\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n",
+ progname, progname);
+ (void) exit(EXIT_FAILURE);
+}
+
+static const char * psxrules;
+static const char * lcltime;
+static const char * directory;
+static const char * leapsec;
+static const char * yitcommand;
+static int sflag = FALSE;
+
+int
+main(argc, argv)
+int argc;
+char * argv[];
+{
+ register int i, j;
+ register int c;
+
+#ifdef unix
+ (void) umask(umask(022) | 022);
+#endif /* defined unix */
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF)
+ switch (c) {
+ default:
+ usage();
+ case 'd':
+ if (directory == NULL)
+ directory = optarg;
+ else {
+ (void) fprintf(stderr,
+"%s: More than one -d option specified\n",
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ case 'l':
+ if (lcltime == NULL)
+ lcltime = optarg;
+ else {
+ (void) fprintf(stderr,
+"%s: More than one -l option specified\n",
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ case 'p':
+ if (psxrules == NULL)
+ psxrules = optarg;
+ else {
+ (void) fprintf(stderr,
+"%s: More than one -p option specified\n",
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ case 'y':
+ if (yitcommand == NULL)
+ yitcommand = optarg;
+ else {
+ (void) fprintf(stderr,
+"%s: More than one -y option specified\n",
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ case 'L':
+ if (leapsec == NULL)
+ leapsec = optarg;
+ else {
+ (void) fprintf(stderr,
+"%s: More than one -L option specified\n",
+ progname);
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ case 'v':
+ noise = TRUE;
+ break;
+ case 's':
+ sflag = TRUE;
+ break;
+ }
+ if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
+ usage(); /* usage message by request */
+ if (directory == NULL)
+ directory = TZDIR;
+ if (yitcommand == NULL)
+ yitcommand = "yearistype";
+
+ setboundaries();
+
+ if (optind < argc && leapsec != NULL) {
+ infile(leapsec);
+ adjleap();
+ }
+
+ zones = (struct zone *) emalloc(0);
+ rules = (struct rule *) emalloc(0);
+ links = (struct link *) emalloc(0);
+ for (i = optind; i < argc; ++i)
+ infile(argv[i]);
+ if (errors)
+ (void) exit(EXIT_FAILURE);
+ associate();
+ for (i = 0; i < nzones; i = j) {
+ /*
+ ** Find the next non-continuation zone entry.
+ */
+ for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
+ continue;
+ outzone(&zones[i], j - i);
+ }
+ /*
+ ** Make links.
+ */
+ for (i = 0; i < nlinks; ++i)
+ dolink(links[i].l_from, links[i].l_to);
+ if (lcltime != NULL)
+ dolink(lcltime, TZDEFAULT);
+ if (psxrules != NULL)
+ dolink(psxrules, TZDEFRULES);
+ return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static void
+dolink(fromfile, tofile)
+const char * const fromfile;
+const char * const tofile;
+{
+ register char * fromname;
+ register char * toname;
+
+ if (fromfile[0] == '/')
+ fromname = (char *)fromfile;
+ else {
+ fromname = ecpyalloc(directory);
+ fromname = ecatalloc(fromname, "/");
+ fromname = ecatalloc(fromname, fromfile);
+ }
+ if (tofile[0] == '/')
+ toname = (char *)tofile;
+ else {
+ toname = ecpyalloc(directory);
+ toname = ecatalloc(toname, "/");
+ toname = ecatalloc(toname, tofile);
+ }
+ /*
+ ** We get to be careful here since
+ ** there's a fair chance of root running us.
+ */
+ if (!itsdir(toname))
+ (void) remove(toname);
+ if (link(fromname, toname) != 0) {
+ if (mkdirs(toname) != 0)
+ (void) exit(EXIT_FAILURE);
+ if (link(fromname, toname) != 0) {
+ (void) fprintf(stderr, "%s: Can't link from %s to ",
+ progname, fromname);
+ (void) perror(toname);
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ if (fromname != fromfile)
+ ifree(fromname);
+ if (toname != tofile)
+ ifree(toname);
+}
+
+static void
+setboundaries()
+{
+ register time_t bit;
+ register int bii;
+
+ for (bit = 1; bit > 0; bit <<= 1)
+ continue;
+ if (bit == 0) { /* time_t is an unsigned type */
+ tt_signed = FALSE;
+ min_time = 0;
+ max_time = ~(time_t) 0;
+ if (sflag)
+ max_time >>= 1;
+ } else {
+ tt_signed = TRUE;
+ min_time = bit;
+ max_time = bit;
+ ++max_time;
+ max_time = -max_time;
+ if (sflag)
+ min_time = 0;
+ }
+ min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
+ max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
+
+ for (bii = 1; bii > 0; bii <<= 1)
+ continue;
+ min_int = bii;
+ max_int = -1 - bii;
+}
+
+static int
+itsdir(name)
+const char * const name;
+{
+ register char * myname;
+ register int accres;
+
+ myname = ecpyalloc(name);
+ myname = ecatalloc(myname, "/.");
+ accres = access(myname, 0);
+ ifree(myname);
+ return accres == 0;
+}
+
+/*
+** Associate sets of rules with zones.
+*/
+
+/*
+** Sort by rule name.
+*/
+
+static int
+rcomp(cp1, cp2)
+const genericptr_t cp1;
+const genericptr_t cp2;
+{
+ return strcmp(((struct rule *) cp1)->r_name,
+ ((struct rule *) cp2)->r_name);
+}
+
+static void
+associate()
+{
+ register struct zone * zp;
+ register struct rule * rp;
+ register int base, out;
+ register int i;
+
+ if (nrules != 0)
+ (void) qsort((genericptr_t) rules,
+ (qsort_size_t) nrules,
+ (qsort_size_t) sizeof *rules, rcomp);
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ zp->z_rules = NULL;
+ zp->z_nrules = 0;
+ }
+ for (base = 0; base < nrules; base = out) {
+ rp = &rules[base];
+ for (out = base + 1; out < nrules; ++out)
+ if (strcmp(rp->r_name, rules[out].r_name) != 0)
+ break;
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (strcmp(zp->z_rule, rp->r_name) != 0)
+ continue;
+ zp->z_rules = rp;
+ zp->z_nrules = out - base;
+ }
+ }
+ for (i = 0; i < nzones; ++i) {
+ zp = &zones[i];
+ if (zp->z_nrules == 0) {
+ /*
+ ** Maybe we have a local standard time offset.
+ */
+ eat(zp->z_filename, zp->z_linenum);
+ zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
+ /*
+ ** Note, though, that if there's no rule,
+ ** a '%s' in the format is a bad thing.
+ */
+ if (strchr(zp->z_format, '%') != 0)
+ error("%s in ruleless zone");
+ }
+ }
+ if (errors)
+ (void) exit(EXIT_FAILURE);
+}
+
+static void
+infile(name)
+const char * name;
+{
+ register FILE * fp;
+ register char ** fields;
+ register char * cp;
+ register const struct lookup * lp;
+ register int nfields;
+ register int wantcont;
+ register int num;
+ char buf[BUFSIZ];
+
+ if (strcmp(name, "-") == 0) {
+ name = "standard input";
+ fp = stdin;
+ } else if ((fp = fopen(name, "r")) == NULL) {
+ (void) fprintf(stderr, "%s: Can't open ", progname);
+ (void) perror(name);
+ (void) exit(EXIT_FAILURE);
+ }
+ wantcont = FALSE;
+ for (num = 1; ; ++num) {
+ eat(name, num);
+ if (fgets(buf, (int) sizeof buf, fp) != buf)
+ break;
+ cp = strchr(buf, '\n');
+ if (cp == NULL) {
+ error("line too long");
+ (void) exit(EXIT_FAILURE);
+ }
+ *cp = '\0';
+ fields = getfields(buf);
+ nfields = 0;
+ while (fields[nfields] != NULL) {
+ static char nada[1];
+
+ if (ciequal(fields[nfields], "-"))
+ fields[nfields] = nada;
+ ++nfields;
+ }
+ if (nfields == 0) {
+ /* nothing to do */
+ } else if (wantcont) {
+ wantcont = inzcont(fields, nfields);
+ } else {
+ lp = byword(fields[0], line_codes);
+ if (lp == NULL)
+ error("input line of unknown type");
+ else switch ((int) (lp->l_value)) {
+ case LC_RULE:
+ inrule(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_ZONE:
+ wantcont = inzone(fields, nfields);
+ break;
+ case LC_LINK:
+ inlink(fields, nfields);
+ wantcont = FALSE;
+ break;
+ case LC_LEAP:
+ if (name != leapsec)
+ (void) fprintf(stderr,
+"%s: Leap line in non leap seconds file %s\n",
+ progname, name);
+ else inleap(fields, nfields);
+ wantcont = FALSE;
+ break;
+ default: /* "cannot happen" */
+ (void) fprintf(stderr,
+"%s: panic: Invalid l_value %d\n",
+ progname, lp->l_value);
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ ifree((char *) fields);
+ }
+ if (ferror(fp)) {
+ (void) fprintf(stderr, "%s: Error reading ", progname);
+ (void) perror(filename);
+ (void) exit(EXIT_FAILURE);
+ }
+ if (fp != stdin && fclose(fp)) {
+ (void) fprintf(stderr, "%s: Error closing ", progname);
+ (void) perror(filename);
+ (void) exit(EXIT_FAILURE);
+ }
+ if (wantcont)
+ error("expected continuation line not found");
+}
+
+/*
+** Convert a string of one of the forms
+** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
+** into a number of seconds.
+** A null string maps to zero.
+** Call error with errstring and return zero on errors.
+*/
+
+static long
+gethms(string, errstring, signable)
+const char * string;
+const char * const errstring;
+const int signable;
+{
+ int hh, mm, ss, sign;
+
+ if (string == NULL || *string == '\0')
+ return 0;
+ if (!signable)
+ sign = 1;
+ else if (*string == '-') {
+ sign = -1;
+ ++string;
+ } else sign = 1;
+ if (sscanf(string, scheck(string, "%d"), &hh) == 1)
+ mm = ss = 0;
+ else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
+ ss = 0;
+ else if (sscanf(string, scheck(string, "%d:%d:%d"),
+ &hh, &mm, &ss) != 3) {
+ error(errstring);
+ return 0;
+ }
+ if (hh < 0 || hh >= HOURSPERDAY ||
+ mm < 0 || mm >= MINSPERHOUR ||
+ ss < 0 || ss > SECSPERMIN) {
+ error(errstring);
+ return 0;
+ }
+ return eitol(sign) *
+ (eitol(hh * MINSPERHOUR + mm) *
+ eitol(SECSPERMIN) + eitol(ss));
+}
+
+static void
+inrule(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ static struct rule r;
+
+ if (nfields != RULE_FIELDS) {
+ error("wrong number of fields on Rule line");
+ return;
+ }
+ if (*fields[RF_NAME] == '\0') {
+ error("nameless rule");
+ return;
+ }
+ r.r_filename = filename;
+ r.r_linenum = linenum;
+ r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
+ rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
+ fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
+ r.r_name = ecpyalloc(fields[RF_NAME]);
+ r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
+ rules = (struct rule *) erealloc((char *) rules,
+ (int) ((nrules + 1) * sizeof *rules));
+ rules[nrules++] = r;
+}
+
+static int
+inzone(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register int i;
+ static char * buf;
+
+ if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
+ error("wrong number of fields on Zone line");
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
+ buf = erealloc(buf, 132 + strlen(TZDEFAULT));
+ (void) sprintf(buf,
+"\"Zone %s\" line and -l option are mutually exclusive",
+ TZDEFAULT);
+ error(buf);
+ return FALSE;
+ }
+ if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
+ buf = erealloc(buf, 132 + strlen(TZDEFRULES));
+ (void) sprintf(buf,
+"\"Zone %s\" line and -p option are mutually exclusive",
+ TZDEFRULES);
+ error(buf);
+ return FALSE;
+ }
+ for (i = 0; i < nzones; ++i)
+ if (zones[i].z_name != NULL &&
+ strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
+ buf = erealloc(buf, 132 +
+ strlen(fields[ZF_NAME]) +
+ strlen(zones[i].z_filename));
+ (void) sprintf(buf,
+"duplicate zone name %s (file \"%s\", line %d)",
+ fields[ZF_NAME],
+ zones[i].z_filename,
+ zones[i].z_linenum);
+ error(buf);
+ return FALSE;
+ }
+ return inzsub(fields, nfields, FALSE);
+}
+
+static int
+inzcont(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
+ error("wrong number of fields on Zone continuation line");
+ return FALSE;
+ }
+ return inzsub(fields, nfields, TRUE);
+}
+
+static int
+inzsub(fields, nfields, iscont)
+register char ** const fields;
+const int nfields;
+const int iscont;
+{
+ register char * cp;
+ static struct zone z;
+ register int i_gmtoff, i_rule, i_format;
+ register int i_untilyear, i_untilmonth;
+ register int i_untilday, i_untiltime;
+ register int hasuntil;
+
+ if (iscont) {
+ i_gmtoff = ZFC_GMTOFF;
+ i_rule = ZFC_RULE;
+ i_format = ZFC_FORMAT;
+ i_untilyear = ZFC_TILYEAR;
+ i_untilmonth = ZFC_TILMONTH;
+ i_untilday = ZFC_TILDAY;
+ i_untiltime = ZFC_TILTIME;
+ z.z_name = NULL;
+ } else {
+ i_gmtoff = ZF_GMTOFF;
+ i_rule = ZF_RULE;
+ i_format = ZF_FORMAT;
+ i_untilyear = ZF_TILYEAR;
+ i_untilmonth = ZF_TILMONTH;
+ i_untilday = ZF_TILDAY;
+ i_untiltime = ZF_TILTIME;
+ z.z_name = ecpyalloc(fields[ZF_NAME]);
+ }
+ z.z_filename = filename;
+ z.z_linenum = linenum;
+ z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
+ if ((cp = strchr(fields[i_format], '%')) != 0) {
+ if (*++cp != 's' || strchr(cp, '%') != 0) {
+ error("invalid abbreviation format");
+ return FALSE;
+ }
+ }
+ z.z_rule = ecpyalloc(fields[i_rule]);
+ z.z_format = ecpyalloc(fields[i_format]);
+ hasuntil = nfields > i_untilyear;
+ if (hasuntil) {
+ z.z_untilrule.r_filename = filename;
+ z.z_untilrule.r_linenum = linenum;
+ rulesub(&z.z_untilrule,
+ fields[i_untilyear],
+ "only",
+ "",
+ (nfields > i_untilmonth) ?
+ fields[i_untilmonth] : "Jan",
+ (nfields > i_untilday) ? fields[i_untilday] : "1",
+ (nfields > i_untiltime) ? fields[i_untiltime] : "0");
+ z.z_untiltime = rpytime(&z.z_untilrule,
+ z.z_untilrule.r_loyear);
+ if (iscont && nzones > 0 &&
+ z.z_untiltime > min_time &&
+ z.z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime > min_time &&
+ zones[nzones - 1].z_untiltime < max_time &&
+ zones[nzones - 1].z_untiltime >= z.z_untiltime) {
+error("Zone continuation line end time is not after end time of previous line");
+ return FALSE;
+ }
+ }
+ zones = (struct zone *) erealloc((char *) zones,
+ (int) ((nzones + 1) * sizeof *zones));
+ zones[nzones++] = z;
+ /*
+ ** If there was an UNTIL field on this line,
+ ** there's more information about the zone on the next line.
+ */
+ return hasuntil;
+}
+
+static void
+inleap(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ register const char * cp;
+ register const struct lookup * lp;
+ register int i, j;
+ int year, month, day;
+ long dayoff, tod;
+ time_t t;
+
+ if (nfields != LEAP_FIELDS) {
+ error("wrong number of fields on Leap line");
+ return;
+ }
+ dayoff = 0;
+ cp = fields[LP_YEAR];
+ if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
+ /*
+ * Leapin' Lizards!
+ */
+ error("invalid leaping year");
+ return;
+ }
+ j = EPOCH_YEAR;
+ while (j != year) {
+ if (year > j) {
+ i = len_years[isleap(j)];
+ ++j;
+ } else {
+ --j;
+ i = -len_years[isleap(j)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
+ error("invalid month name");
+ return;
+ }
+ month = lp->l_value;
+ j = TM_JANUARY;
+ while (j != month) {
+ i = len_months[isleap(year)][j];
+ dayoff = oadd(dayoff, eitol(i));
+ ++j;
+ }
+ cp = fields[LP_DAY];
+ if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
+ day <= 0 || day > len_months[isleap(year)][month]) {
+ error("invalid day of month");
+ return;
+ }
+ dayoff = oadd(dayoff, eitol(day - 1));
+ if (dayoff < 0 && !tt_signed) {
+ error("time before zero");
+ return;
+ }
+ t = (time_t) dayoff * SECSPERDAY;
+ /*
+ ** Cheap overflow check.
+ */
+ if (t / SECSPERDAY != dayoff) {
+ error("time overflow");
+ return;
+ }
+ tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
+ cp = fields[LP_CORR];
+ {
+ register int positive;
+ int count;
+
+ if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
+ positive = FALSE;
+ count = 1;
+ } else if (strcmp(cp, "--") == 0) {
+ positive = FALSE;
+ count = 2;
+ } else if (strcmp(cp, "+") == 0) {
+ positive = TRUE;
+ count = 1;
+ } else if (strcmp(cp, "++") == 0) {
+ positive = TRUE;
+ count = 2;
+ } else {
+ error("illegal CORRECTION field on Leap line");
+ return;
+ }
+ if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
+ error("illegal Rolling/Stationary field on Leap line");
+ return;
+ }
+ leapadd(tadd(t, tod), positive, lp->l_value, count);
+ }
+}
+
+static void
+inlink(fields, nfields)
+register char ** const fields;
+const int nfields;
+{
+ struct link l;
+
+ if (nfields != LINK_FIELDS) {
+ error("wrong number of fields on Link line");
+ return;
+ }
+ if (*fields[LF_FROM] == '\0') {
+ error("blank FROM field on Link line");
+ return;
+ }
+ if (*fields[LF_TO] == '\0') {
+ error("blank TO field on Link line");
+ return;
+ }
+ l.l_filename = filename;
+ l.l_linenum = linenum;
+ l.l_from = ecpyalloc(fields[LF_FROM]);
+ l.l_to = ecpyalloc(fields[LF_TO]);
+ links = (struct link *) erealloc((char *) links,
+ (int) ((nlinks + 1) * sizeof *links));
+ links[nlinks++] = l;
+}
+
+static void
+rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
+register struct rule * const rp;
+char * const loyearp;
+char * const hiyearp;
+char * const typep;
+char * const monthp;
+char * const dayp;
+char * const timep;
+{
+ register struct lookup const * lp;
+ register char * cp;
+
+ if ((lp = byword(monthp, mon_names)) == NULL) {
+ error("invalid month name");
+ return;
+ }
+ rp->r_month = lp->l_value;
+ rp->r_todisstd = FALSE;
+ cp = timep;
+ if (*cp != '\0') {
+ cp += strlen(cp) - 1;
+ switch (lowerit(*cp)) {
+ case 's':
+ rp->r_todisstd = TRUE;
+ *cp = '\0';
+ break;
+ case 'w':
+ rp->r_todisstd = FALSE;
+ *cp = '\0';
+ break;
+ }
+ }
+ rp->r_tod = gethms(timep, "invalid time of day", FALSE);
+ /*
+ ** Year work.
+ */
+ cp = loyearp;
+ if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_loyear = min_int;
+ break;
+ case YR_MAXIMUM:
+ rp->r_loyear = max_int;
+ break;
+ default: /* "cannot happen" */
+ (void) fprintf(stderr,
+ "%s: panic: Invalid l_value %d\n",
+ progname, lp->l_value);
+ (void) exit(EXIT_FAILURE);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
+ error("invalid starting year");
+ return;
+ }
+ cp = hiyearp;
+ if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
+ case YR_MINIMUM:
+ rp->r_hiyear = min_int;
+ break;
+ case YR_MAXIMUM:
+ rp->r_hiyear = max_int;
+ break;
+ case YR_ONLY:
+ rp->r_hiyear = rp->r_loyear;
+ break;
+ default: /* "cannot happen" */
+ (void) fprintf(stderr,
+ "%s: panic: Invalid l_value %d\n",
+ progname, lp->l_value);
+ (void) exit(EXIT_FAILURE);
+ } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
+ error("invalid ending year");
+ return;
+ }
+ if (rp->r_loyear > rp->r_hiyear) {
+ error("starting year greater than ending year");
+ return;
+ }
+ if (*typep == '\0')
+ rp->r_yrtype = NULL;
+ else {
+ if (rp->r_loyear == rp->r_hiyear) {
+ error("typed single year");
+ return;
+ }
+ rp->r_yrtype = ecpyalloc(typep);
+ }
+ /*
+ ** Day work.
+ ** Accept things such as:
+ ** 1
+ ** last-Sunday
+ ** Sun<=20
+ ** Sun>=7
+ */
+ if ((lp = byword(dayp, lasts)) != NULL) {
+ rp->r_dycode = DC_DOWLEQ;
+ rp->r_wday = lp->l_value;
+ rp->r_dayofmonth = len_months[1][rp->r_month];
+ } else {
+ if ((cp = strchr(dayp, '<')) != 0)
+ rp->r_dycode = DC_DOWLEQ;
+ else if ((cp = strchr(dayp, '>')) != 0)
+ rp->r_dycode = DC_DOWGEQ;
+ else {
+ cp = dayp;
+ rp->r_dycode = DC_DOM;
+ }
+ if (rp->r_dycode != DC_DOM) {
+ *cp++ = 0;
+ if (*cp++ != '=') {
+ error("invalid day of month");
+ return;
+ }
+ if ((lp = byword(dayp, wday_names)) == NULL) {
+ error("invalid weekday name");
+ return;
+ }
+ rp->r_wday = lp->l_value;
+ }
+ if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
+ rp->r_dayofmonth <= 0 ||
+ (rp->r_dayofmonth > len_months[1][rp->r_month])) {
+ error("invalid day of month");
+ return;
+ }
+ }
+}
+
+static void
+convert(val, buf)
+const long val;
+char * const buf;
+{
+ register int i;
+ register long shift;
+
+ for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
+ buf[i] = val >> shift;
+}
+
+static void
+puttzcode(val, fp)
+const long val;
+FILE * const fp;
+{
+ char buf[4];
+
+ convert(val, buf);
+ (void) fwrite((genericptr_t) buf,
+ (fwrite_size_t) sizeof buf,
+ (fwrite_size_t) 1, fp);
+}
+
+static void
+writezone(name)
+const char * const name;
+{
+ register FILE * fp;
+ register int i, j;
+ static char * fullname;
+ static struct tzhead tzh;
+
+ fullname = erealloc(fullname,
+ strlen(directory) + 1 + strlen(name) + 1);
+ (void) sprintf(fullname, "%s/%s", directory, name);
+ if ((fp = fopen(fullname, "wb")) == NULL) {
+ if (mkdirs(fullname) != 0)
+ (void) exit(EXIT_FAILURE);
+ if ((fp = fopen(fullname, "wb")) == NULL) {
+ (void) fprintf(stderr, "%s: Can't create ", progname);
+ (void) perror(fullname);
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ convert(eitol(typecnt), tzh.tzh_ttisstdcnt);
+ convert(eitol(leapcnt), tzh.tzh_leapcnt);
+ convert(eitol(timecnt), tzh.tzh_timecnt);
+ convert(eitol(typecnt), tzh.tzh_typecnt);
+ convert(eitol(charcnt), tzh.tzh_charcnt);
+ (void) fwrite((genericptr_t) &tzh,
+ (fwrite_size_t) sizeof tzh,
+ (fwrite_size_t) 1, fp);
+ for (i = 0; i < timecnt; ++i) {
+ j = leapcnt;
+ while (--j >= 0)
+ if (ats[i] >= trans[j]) {
+ ats[i] = tadd(ats[i], corr[j]);
+ break;
+ }
+ puttzcode((long) ats[i], fp);
+ }
+ if (timecnt > 0)
+ (void) fwrite((genericptr_t) types,
+ (fwrite_size_t) sizeof types[0],
+ (fwrite_size_t) timecnt, fp);
+ for (i = 0; i < typecnt; ++i) {
+ puttzcode((long) gmtoffs[i], fp);
+ (void) putc(isdsts[i], fp);
+ (void) putc(abbrinds[i], fp);
+ }
+ if (charcnt != 0)
+ (void) fwrite((genericptr_t) chars,
+ (fwrite_size_t) sizeof chars[0],
+ (fwrite_size_t) charcnt, fp);
+ for (i = 0; i < leapcnt; ++i) {
+ if (roll[i]) {
+ if (timecnt == 0 || trans[i] < ats[0]) {
+ j = 0;
+ while (isdsts[j])
+ if (++j >= typecnt) {
+ j = 0;
+ break;
+ }
+ } else {
+ j = 1;
+ while (j < timecnt && trans[i] >= ats[j])
+ ++j;
+ j = types[j - 1];
+ }
+ puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
+ } else puttzcode((long) trans[i], fp);
+ puttzcode((long) corr[i], fp);
+ }
+ for (i = 0; i < typecnt; ++i)
+ (void) putc(ttisstds[i], fp);
+ if (ferror(fp) || fclose(fp)) {
+ (void) fprintf(stderr, "%s: Write error on ", progname);
+ (void) perror(fullname);
+ (void) exit(EXIT_FAILURE);
+ }
+}
+
+static void
+outzone(zpfirst, zonecount)
+const struct zone * const zpfirst;
+const int zonecount;
+{
+ register const struct zone * zp;
+ register struct rule * rp;
+ register int i, j;
+ register int usestart, useuntil;
+ register time_t starttime, untiltime;
+ register long gmtoff;
+ register long stdoff;
+ register int year;
+ register long startoff;
+ register int startisdst;
+ register int startttisstd;
+ register int type;
+ char startbuf[BUFSIZ];
+
+ /*
+ ** Now. . .finally. . .generate some useful data!
+ */
+ timecnt = 0;
+ typecnt = 0;
+ charcnt = 0;
+ /*
+ ** A guess that may well be corrected later.
+ */
+ stdoff = 0;
+ /*
+ ** Thanks to Earl Chew (earl@dnd.icp.nec.com.au)
+ ** for noting the need to unconditionally initialize startttisstd.
+ */
+ startttisstd = FALSE;
+#ifdef lint
+ starttime = 0;
+#endif /* defined lint */
+ for (i = 0; i < zonecount; ++i) {
+ zp = &zpfirst[i];
+ usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
+ useuntil = i < (zonecount - 1);
+ if (useuntil && zp->z_untiltime <= min_time)
+ continue;
+ gmtoff = zp->z_gmtoff;
+ eat(zp->z_filename, zp->z_linenum);
+ startisdst = -1;
+ if (zp->z_nrules == 0) {
+ stdoff = zp->z_stdoff;
+ (void) strcpy(startbuf, zp->z_format);
+ type = addtype(oadd(zp->z_gmtoff, stdoff),
+ startbuf, stdoff != 0, startttisstd);
+ if (usestart)
+ addtt(starttime, type);
+ else if (stdoff != 0)
+ addtt(min_time, type);
+ } else for (year = min_year; year <= max_year; ++year) {
+ if (useuntil && year > zp->z_untilrule.r_hiyear)
+ break;
+ /*
+ ** Mark which rules to do in the current year.
+ ** For those to do, calculate rpytime(rp, year);
+ */
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ rp->r_todo = year >= rp->r_loyear &&
+ year <= rp->r_hiyear &&
+ yearistype(year, rp->r_yrtype);
+ if (rp->r_todo)
+ rp->r_temp = rpytime(rp, year);
+ }
+ for ( ; ; ) {
+ register int k;
+ register time_t jtime, ktime;
+ register long offset;
+ char buf[BUFSIZ];
+
+ if (useuntil) {
+ /*
+ ** Turn untiltime into GMT
+ ** assuming the current gmtoff and
+ ** stdoff values.
+ */
+ untiltime = tadd(zp->z_untiltime,
+ -gmtoff);
+ if (!zp->z_untilrule.r_todisstd)
+ untiltime = tadd(untiltime,
+ -stdoff);
+ }
+ /*
+ ** Find the rule (of those to do, if any)
+ ** that takes effect earliest in the year.
+ */
+ k = -1;
+#ifdef lint
+ ktime = 0;
+#endif /* defined lint */
+ for (j = 0; j < zp->z_nrules; ++j) {
+ rp = &zp->z_rules[j];
+ if (!rp->r_todo)
+ continue;
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ offset = gmtoff;
+ if (!rp->r_todisstd)
+ offset = oadd(offset, stdoff);
+ jtime = rp->r_temp;
+ if (jtime == min_time ||
+ jtime == max_time)
+ continue;
+ jtime = tadd(jtime, -offset);
+ if (k < 0 || jtime < ktime) {
+ k = j;
+ ktime = jtime;
+ }
+ }
+ if (k < 0)
+ break; /* go on to next year */
+ rp = &zp->z_rules[k];
+ rp->r_todo = FALSE;
+ if (useuntil && ktime >= untiltime)
+ break;
+ if (usestart) {
+ if (ktime < starttime) {
+ stdoff = rp->r_stdoff;
+ startoff = oadd(zp->z_gmtoff,
+ rp->r_stdoff);
+ (void) sprintf(startbuf, zp->z_format,
+ rp->r_abbrvar);
+ startisdst = rp->r_stdoff != 0;
+ continue;
+ }
+ usestart = FALSE;
+ if (ktime != starttime) {
+ if (startisdst < 0 &&
+ zp->z_gmtoff !=
+ (zp - 1)->z_gmtoff) {
+ type = (timecnt == 0) ? 0 :
+ types[timecnt - 1];
+ startoff = oadd(gmtoffs[type],
+ -(zp - 1)->z_gmtoff);
+ startisdst = startoff != 0;
+ startoff = oadd(startoff,
+ zp->z_gmtoff);
+ (void) strcpy(startbuf,
+ &chars[abbrinds[type]]);
+ }
+ if (startisdst >= 0)
+addtt(starttime, addtype(startoff, startbuf, startisdst, startttisstd));
+ }
+ }
+ eats(zp->z_filename, zp->z_linenum,
+ rp->r_filename, rp->r_linenum);
+ (void) sprintf(buf, zp->z_format,
+ rp->r_abbrvar);
+ offset = oadd(zp->z_gmtoff, rp->r_stdoff);
+ type = addtype(offset, buf, rp->r_stdoff != 0,
+ rp->r_todisstd);
+ addtt(ktime, type);
+ stdoff = rp->r_stdoff;
+ }
+ }
+ /*
+ ** Now we may get to set starttime for the next zone line.
+ */
+ if (useuntil) {
+ starttime = tadd(zp->z_untiltime, -gmtoff);
+ startttisstd = zp->z_untilrule.r_todisstd;
+ if (!startttisstd)
+ starttime = tadd(starttime, -stdoff);
+ }
+ }
+ writezone(zpfirst->z_name);
+}
+
+static void
+addtt(starttime, type)
+const time_t starttime;
+const int type;
+{
+ if (timecnt != 0 && type == types[timecnt - 1])
+ return; /* easy enough! */
+ if (timecnt == 0 && type == 0 && isdsts[0] == 0)
+ return; /* handled by default rule */
+ if (timecnt >= TZ_MAX_TIMES) {
+ error("too many transitions?!");
+ (void) exit(EXIT_FAILURE);
+ }
+ ats[timecnt] = starttime;
+ types[timecnt] = type;
+ ++timecnt;
+}
+
+static int
+addtype(gmtoff, abbr, isdst, ttisstd)
+const long gmtoff;
+const char * const abbr;
+const int isdst;
+const int ttisstd;
+{
+ register int i, j;
+
+ /*
+ ** See if there's already an entry for this zone type.
+ ** If so, just return its index.
+ */
+ for (i = 0; i < typecnt; ++i) {
+ if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
+ strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
+ ttisstd == ttisstds[i])
+ return i;
+ }
+ /*
+ ** There isn't one; add a new one, unless there are already too
+ ** many.
+ */
+ if (typecnt >= TZ_MAX_TYPES) {
+ error("too many local time types");
+ (void) exit(EXIT_FAILURE);
+ }
+ gmtoffs[i] = gmtoff;
+ isdsts[i] = isdst;
+ ttisstds[i] = ttisstd;
+
+ for (j = 0; j < charcnt; ++j)
+ if (strcmp(&chars[j], abbr) == 0)
+ break;
+ if (j == charcnt)
+ newabbr(abbr);
+ abbrinds[i] = j;
+ ++typecnt;
+ return i;
+}
+
+static void
+leapadd(t, positive, rolling, count)
+const time_t t;
+const int positive;
+const int rolling;
+int count;
+{
+ register int i, j;
+
+ if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
+ error("too many leap seconds");
+ (void) exit(EXIT_FAILURE);
+ }
+ for (i = 0; i < leapcnt; ++i)
+ if (t <= trans[i]) {
+ if (t == trans[i]) {
+ error("repeated leap second moment");
+ (void) exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ do {
+ for (j = leapcnt; j > i; --j) {
+ trans[j] = trans[j - 1];
+ corr[j] = corr[j - 1];
+ roll[j] = roll[j - 1];
+ }
+ trans[i] = t;
+ corr[i] = positive ? 1L : eitol(-count);
+ roll[i] = rolling;
+ ++leapcnt;
+ } while (positive && --count != 0);
+}
+
+static void
+adjleap()
+{
+ register int i;
+ register long last = 0;
+
+ /*
+ ** propagate leap seconds forward
+ */
+ for (i = 0; i < leapcnt; ++i) {
+ trans[i] = tadd(trans[i], last);
+ last = corr[i] += last;
+ }
+}
+
+static int
+yearistype(year, type)
+const int year;
+const char * const type;
+{
+ static char * buf;
+ int result;
+
+ if (type == NULL || *type == '\0')
+ return TRUE;
+ if (strcmp(type, "uspres") == 0)
+ return (year % 4) == 0;
+ if (strcmp(type, "nonpres") == 0)
+ return (year % 4) != 0;
+ buf = erealloc(buf, 132 + strlen(yitcommand) + strlen(type));
+ (void) sprintf(buf, "%s %d %s", yitcommand, year, type);
+ result = system(buf);
+ if (result == 0)
+ return TRUE;
+ if (result == (1 << 8))
+ return FALSE;
+ error("Wild result from command execution");
+ (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
+ progname, buf, result);
+ for ( ; ; )
+ (void) exit(EXIT_FAILURE);
+}
+
+static int
+lowerit(a)
+const int a;
+{
+ return (isascii(a) && isupper(a)) ? tolower(a) : a;
+}
+
+static int
+ciequal(ap, bp) /* case-insensitive equality */
+register const char * ap;
+register const char * bp;
+{
+ while (lowerit(*ap) == lowerit(*bp++))
+ if (*ap++ == '\0')
+ return TRUE;
+ return FALSE;
+}
+
+static int
+itsabbr(abbr, word)
+register const char * abbr;
+register const char * word;
+{
+ if (lowerit(*abbr) != lowerit(*word))
+ return FALSE;
+ ++word;
+ while (*++abbr != '\0')
+ do if (*word == '\0')
+ return FALSE;
+ while (lowerit(*word++) != lowerit(*abbr));
+ return TRUE;
+}
+
+static const struct lookup *
+byword(word, table)
+register const char * const word;
+register const struct lookup * const table;
+{
+ register const struct lookup * foundlp;
+ register const struct lookup * lp;
+
+ if (word == NULL || table == NULL)
+ return NULL;
+ /*
+ ** Look for exact match.
+ */
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (ciequal(word, lp->l_word))
+ return lp;
+ /*
+ ** Look for inexact match.
+ */
+ foundlp = NULL;
+ for (lp = table; lp->l_word != NULL; ++lp)
+ if (itsabbr(word, lp->l_word))
+ if (foundlp == NULL)
+ foundlp = lp;
+ else return NULL; /* multiple inexact matches */
+ return foundlp;
+}
+
+static char **
+getfields(cp)
+register char * cp;
+{
+ register char * dp;
+ register char ** array;
+ register int nsubs;
+
+ if (cp == NULL)
+ return NULL;
+ array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
+ nsubs = 0;
+ for ( ; ; ) {
+ while (isascii(*cp) && isspace(*cp))
+ ++cp;
+ if (*cp == '\0' || *cp == '#')
+ break;
+ array[nsubs++] = dp = cp;
+ do {
+ if ((*dp = *cp++) != '"')
+ ++dp;
+ else while ((*dp = *cp++) != '"')
+ if (*dp != '\0')
+ ++dp;
+ else error("Odd number of quotation marks");
+ } while (*cp != '\0' && *cp != '#' &&
+ (!isascii(*cp) || !isspace(*cp)));
+ if (isascii(*cp) && isspace(*cp))
+ ++cp;
+ *dp = '\0';
+ }
+ array[nsubs] = NULL;
+ return array;
+}
+
+static long
+oadd(t1, t2)
+const long t1;
+const long t2;
+{
+ register long t;
+
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error("time overflow");
+ (void) exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+static time_t
+tadd(t1, t2)
+const time_t t1;
+const long t2;
+{
+ register time_t t;
+
+ if (t1 == max_time && t2 > 0)
+ return max_time;
+ if (t1 == min_time && t2 < 0)
+ return min_time;
+ t = t1 + t2;
+ if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
+ error("time overflow");
+ (void) exit(EXIT_FAILURE);
+ }
+ return t;
+}
+
+/*
+** Given a rule, and a year, compute the date - in seconds since January 1,
+** 1970, 00:00 LOCAL time - in that year that the rule refers to.
+*/
+
+static time_t
+rpytime(rp, wantedy)
+register const struct rule * const rp;
+register const int wantedy;
+{
+ register int y, m, i;
+ register long dayoff; /* with a nod to Margaret O. */
+ register time_t t;
+
+ if (wantedy == min_int)
+ return min_time;
+ if (wantedy == max_int)
+ return max_time;
+ dayoff = 0;
+ m = TM_JANUARY;
+ y = EPOCH_YEAR;
+ while (wantedy != y) {
+ if (wantedy > y) {
+ i = len_years[isleap(y)];
+ ++y;
+ } else {
+ --y;
+ i = -len_years[isleap(y)];
+ }
+ dayoff = oadd(dayoff, eitol(i));
+ }
+ while (m != rp->r_month) {
+ i = len_months[isleap(y)][m];
+ dayoff = oadd(dayoff, eitol(i));
+ ++m;
+ }
+ i = rp->r_dayofmonth;
+ if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
+ if (rp->r_dycode == DC_DOWLEQ)
+ --i;
+ else {
+ error("use of 2/29 in non leap-year");
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ --i;
+ dayoff = oadd(dayoff, eitol(i));
+ if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
+ register long wday;
+
+#define LDAYSPERWEEK ((long) DAYSPERWEEK)
+ wday = eitol(EPOCH_WDAY);
+ /*
+ ** Don't trust mod of negative numbers.
+ */
+ if (dayoff >= 0)
+ wday = (wday + dayoff) % LDAYSPERWEEK;
+ else {
+ wday -= ((-dayoff) % LDAYSPERWEEK);
+ if (wday < 0)
+ wday += LDAYSPERWEEK;
+ }
+ while (wday != eitol(rp->r_wday))
+ if (rp->r_dycode == DC_DOWGEQ) {
+ dayoff = oadd(dayoff, (long) 1);
+ if (++wday >= LDAYSPERWEEK)
+ wday = 0;
+ ++i;
+ } else {
+ dayoff = oadd(dayoff, (long) -1);
+ if (--wday < 0)
+ wday = LDAYSPERWEEK - 1;
+ --i;
+ }
+ if (i < 0 || i >= len_months[isleap(y)][m]) {
+ error("no day in month matches rule");
+ (void) exit(EXIT_FAILURE);
+ }
+ }
+ if (dayoff < 0 && !tt_signed)
+ return min_time;
+ t = (time_t) dayoff * SECSPERDAY;
+ /*
+ ** Cheap overflow check.
+ */
+ if (t / SECSPERDAY != dayoff)
+ return (dayoff > 0) ? max_time : min_time;
+ return tadd(t, rp->r_tod);
+}
+
+static void
+newabbr(string)
+const char * const string;
+{
+ register int i;
+
+ i = strlen(string) + 1;
+ if (charcnt + i > TZ_MAX_CHARS) {
+ error("too many, or too long, time zone abbreviations");
+ (void) exit(EXIT_FAILURE);
+ }
+ (void) strcpy(&chars[charcnt], string);
+ charcnt += eitol(i);
+}
+
+static int
+mkdirs(argname)
+char * const argname;
+{
+ register char * name;
+ register char * cp;
+
+ if (argname == NULL || *argname == '\0')
+ return 0;
+ cp = name = ecpyalloc(argname);
+ while ((cp = strchr(cp + 1, '/')) != 0) {
+ *cp = '\0';
+#ifndef unix
+ /*
+ ** MS-DOS drive specifier?
+ */
+ if (strlen(name) == 2 && isascii(name[0]) &&
+ isalpha(name[0]) && name[1] == ':') {
+ *cp = '/';
+ continue;
+ }
+#endif /* !defined unix */
+ if (!itsdir(name)) {
+ /*
+ ** It doesn't seem to exist, so we try to create it.
+ */
+ if (emkdir(name, 0755) != 0) {
+ (void) fprintf(stderr,
+ "%s: Can't create directory ",
+ progname);
+ (void) perror(name);
+ ifree(name);
+ return -1;
+ }
+ }
+ *cp = '/';
+ }
+ ifree(name);
+ return 0;
+}
+
+static long
+eitol(i)
+const int i;
+{
+ long l;
+
+ l = i;
+ if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
+ (void) fprintf(stderr,
+ "%s: %d did not sign extend correctly\n",
+ progname, i);
+ (void) exit(EXIT_FAILURE);
+ }
+ return l;
+}
+
+/*
+** UNIX is a registered trademark of AT&T.
+*/
diff --git a/usr.sbin/zic/zic/Makefile b/usr.sbin/zic/zic/Makefile
new file mode 100644
index 0000000..5331112
--- /dev/null
+++ b/usr.sbin/zic/zic/Makefile
@@ -0,0 +1,13 @@
+# $Id$
+
+.PATH: ${.CURDIR}/..
+
+PROG= zic
+
+SRCS= zic.c ialloc.c scheck.c
+MAN8= ${.CURDIR}/../zic.8
+CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../lib/libc/stdtime
+CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+
+.include <bsd.prog.mk>
OpenPOWER on IntegriCloud