Index: head/UPDATING =================================================================== --- head/UPDATING (revision 337496) +++ head/UPDATING (revision 337497) @@ -1,1785 +1,1790 @@ Updating Information for FreeBSD current users. This file is maintained and copyrighted by M. Warner Losh . See end of file for further details. For commonly done items, please see the COMMON ITEMS: section later in the file. These instructions assume that you basically know what you are doing. If not, then please consult the FreeBSD handbook: https://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html Items affecting the ports and packages system can be found in /usr/ports/UPDATING. Please read that file before running portupgrade. NOTE: FreeBSD has switched from gcc to clang. If you have trouble bootstrapping from older versions of FreeBSD, try WITHOUT_CLANG and WITH_GCC to bootstrap to the tip of head, and then rebuild without this option. The bootstrap process from older version of current across the gcc/clang cutover is a bit fragile. NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW: FreeBSD 12.x has many debugging features turned on, in both the kernel and userland. These features attempt to detect incorrect use of system primitives, and encourage loud failure through extra sanity checking and fail stop semantics. They also substantially impact system performance. If you want to do performance measurement, benchmarking, and optimization, you'll want to turn them off. This includes various WITNESS- related kernel options, INVARIANTS, malloc debugging flags in userland, and various verbose features in the kernel. Many developers choose to disable these features on build machines to maximize performance. (To completely disable malloc debugging, define MALLOC_PRODUCTION in /etc/make.conf, or to merely disable the most expensive debugging functionality run "ln -s 'abort:false,junk:false' /etc/malloc.conf".) +20180808: + The default pager for most commands has been changed to "less". To + restore the old behavior, set PAGER="more" and MANPAGER="more -s" in + your environment. + 20180731: The jedec_ts(4) driver has been removed. A superset of its functionality is available in the jedec_dimm(4) driver, and the manpage for that driver includes migration instructions. If you have "device jedec_ts" in your kernel configuration file, it must be removed. 20180730: amd64/GENERIC now has EFI runtime services, EFIRT, enabled by default. This should have no effect if the kernel is booted via BIOS/legacy boot. EFIRT may be disabled via a loader tunable, efi.rt.disabled, if a system has a buggy firmware that prevents a successful boot due to use of runtime services. 20180727: Atmel AT91RM9200 and AT91SAM9, Cavium CNS 11xx and XScale support has been removed from the tree. These ports were obsolete and/or known to be broken for many years. 20180723: loader.efi has been augmented to participate more fully in the UEFI boot manager protocol. loader.efi will now look at the BootXXXX environment variable to determine if a specific kernel or root partition was specified. XXXX is derived from BootCurrent. efibootmgr(8) manages these standard UEFI variables. 20180720: zfsloader's functionality has now been folded into loader. zfsloader is no longer necessary once you've updated your boot blocks. For a transition period, we will install a hardlink for zfsloader to loader to allow a smooth transition until the boot blocks can be updated (hard link because old zfs boot blocks don't understand symlinks). 20180719: ARM64 now have efifb support, if you want to have serial console on your arm64 board when an screen is connected and the bootloader setup a frambuffer for us to use, just add : boot_serial=YES boot_multicons=YES in /boot/loader.conf For Raspberry Pi 3 (RPI) users, this is needed even if you don't have an screen connected as the firmware will setup a framebuffer are that u-boot will expose as an EFI framebuffer. 20180719: New uid:gid added, ntpd:ntpd (123:123). Be sure to run mergemaster or take steps to update /etc/passwd before doing installworld on existing systems. Also, rc.d/ntpd now starts ntpd(8) as user ntpd if the new mac_ntpd(4) policy is available, unless ntpd_flags or the ntp config file contain options that change file/dir locations. When such options (e.g., "statsdir" or "crypto") are used, ntpd can still be run as non-root by setting ntpd_user=ntpd in rc.conf, after taking steps to ensure that all required files/dirs are accessible by the ntpd user. 20180717: Big endian arm support has been removed. 20180711: The static environment setup in kernel configs is no longer mutually exclusive with the loader(8) environment by default. In order to restore the previous default behavior of disabling the loader(8) environment if a static environment is present, you must specify loader_env.disabled=1 in the static environment. 20180705: The ABI of syscalls used by management tools like sockstat and netstat has been broken to allow 32-bit binaries to work on 64-bit kernels without modification. These programs will need to match the kernel in order to function. External programs may require minor modifications to accommodate a change of type in structures from pointers to 64-bit virtual addresses. 20180702: On i386 and amd64 atomics are now inlined. Out of tree modules using atomics will need to be rebuilt. 20180701: The '%I' format in the kern.corefile sysctl limits the number of core files that a process can generate to the number stored in the debug.ncores sysctl. The '%I' format is replaced by the single digit index. Previously, if all indexes were taken the kernel would overwrite only a core file with the highest index in a filename. Currently the system will create a new core file if there is a free index or if all slots are taken it will overwrite the oldest one. 20180630: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180628: r335753 introduced a new quoting method. However, etc/devd/devmatch.conf needed to be changed to work with it. This change was made with r335763 and requires a mergemaster / etcupdate / etc to update the installed file. 20180612: r334930 changed the interface between the NFS modules, so they all need to be rebuilt. r335018 did a __FreeBSD_version bump for this. 20180530: The kernel / userland interface for devinfo changed, so you'll need a new kernel and userland as a pair for it to work (rebuilding lib/libdevinfo is all that's required). devinfo and devmatch will not work, but everything else will when there's a mismatch. 20180523: The on-disk format for hwpmc callchain records has changed to include threadid corresponding to a given record. This changes the field offsets and thus requires that libpmcstat be rebuilt before using a kernel later than r334108. 20180517: The vxge(4) driver has been removed. This driver was introduced into HEAD one week before the Exar left the Ethernet market and is not known to be used. If you have device vxge in your kernel config file it must be removed. 20180510: The amd64 kernel now requires a ld that supports ifunc to produce a working kernel, either lld or a newer binutils. lld is built by default on amd64, and the 'buildkernel' target uses it automatically. However, it is not the default linker, so building the kernel the traditional way requires LD=ld.lld on the command line (or LD=/usr/local/bin/ld for binutils port/package). lld will soon be default, and this requirement will go away. 20180508: The nxge(4) driver has been removed. This driver was for PCI-X 10g cards made by s2io/Neterion. The company was aquired by Exar and no longer sells or supports Ethernet products. If you have device nxge in your kernel config file it must be removed. 20180504: The tz database (tzdb) has been updated to 2018e. This version more correctly models time stamps in time zones with negative DST such as Europe/Dublin (from 1971 on), Europe/Prague (1946/7), and Africa/Windhoek (1994/2017). This does not affect the UT offsets, only time zone abbreviations and the tm_isdst flag. 20180502: The ixgb(4) driver has been removed. This driver was for an early and uncommon legacy PCI 10GbE for a single ASIC, Intel 82597EX. Intel quickly shifted to the long lived ixgbe family. If you have device ixgb in your kernel config file it must be removed. 20180501: The lmc(4) driver has been removed. This was a WAN interface card that was already reportedly rare in 2003, and had an ambiguous license. If you have device lmc in your kernel config file it must be removed. 20180413: Support for Arcnet networks has been removed. If you have device arcnet or device cm in your kernel config file they must be removed. 20180411: Support for FDDI networks has been removed. If you have device fddi or device fpa in your kernel config file they must be removed. 20180406: In addition to supporting RFC 3164 formatted messages, the syslogd(8) service is now capable of parsing RFC 5424 formatted log messages. The main benefit of using RFC 5424 is that clients may now send log messages with timestamps containing year numbers, microseconds and time zone offsets. Similarly, the syslog(3) C library function has been altered to send RFC 5424 formatted messages to the local system logging daemon. On systems using syslogd(8), this change should have no negative impact, as long as syslogd(8) and the C library are updated at the same time. On systems using a different system logging daemon, it may be necessary to make configuration adjustments, depending on the software used. When using syslog-ng, add the 'syslog-protocol' flag to local input sources to enable parsing of RFC 5424 formatted messages: source src { unix-dgram("/var/run/log" flags(syslog-protocol)); } When using rsyslog, disable the 'SysSock.UseSpecialParser' option of the 'imuxsock' module to let messages be processed by the regular RFC 3164/5424 parsing pipeline: module(load="imuxsock" SysSock.UseSpecialParser="off") Do note that these changes only affect communication between local applications and syslogd(8). The format that syslogd(8) uses to store messages on disk or forward messages to other systems remains unchanged. syslogd(8) still uses RFC 3164 for these purposes. Options to customize this behaviour will be added in the future. Utilities that process log files stored in /var/log are thus expected to continue to function as before. __FreeBSD_version has been incremented to 1200061 to denote this change. 20180328: Support for token ring networks has been removed. If you have "device token" in your kernel config you should remove it. No device drivers supported token ring. 20180323: makefs was modified to be able to tag ISO9660 El Torito boot catalog entries as EFI instead of overloading the i386 tag as done previously. The amd64 mkisoimages.sh script used to build amd64 ISO images for release was updated to use this. This may mean that makefs must be updated before "make cdrom" can be run in the release directory. This should be as simple as: $ cd $SRCDIR/usr.sbin/makefs $ make depend all install 20180212: FreeBSD boot loader enhanced with Lua scripting. It's purely opt-in for now by building WITH_LOADER_LUA and WITHOUT_FORTH in /etc/src.conf. Co-existance for the transition period will come shortly. Booting is a complex environment and test coverage for Lua-enabled loaders has been thin, so it would be prudent to assume it might not work and make provisions for backup boot methods. 20180211: devmatch functionality has been turned on in devd. It will automatically load drivers for unattached devices. This may cause unexpected drivers to be loaded. Please report any problems to current@ and imp@freebsd.org. 20180114: Clang, llvm, lld, lldb, compiler-rt and libc++ have been upgraded to 6.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20180110: LLVM's lld linker is now used as the FreeBSD/amd64 bootstrap linker. This means it is used to link the kernel and userland libraries and executables, but is not yet installed as /usr/bin/ld by default. To revert to ld.bfd as the bootstrap linker, in /etc/src.conf set WITHOUT_LLD_BOOTSTRAP=yes 20180110: On i386, pmtimer has been removed. Its functionality has been folded into apm. It was a no-op on ACPI in current for a while now (but was still needed on i386 in FreeBSD 11 and earlier). Users may need to remove it from kernel config files. 20180104: The use of RSS hash from the network card aka flowid has been disabled by default for lagg(4) as it's currently incompatible with the lacp and loadbalance protocols. This can be re-enabled by setting the following in loader.conf: net.link.lagg.default_use_flowid="1" 20180102: The SW_WATCHDOG option is no longer necessary to enable the hardclock-based software watchdog if no hardware watchdog is configured. As before, SW_WATCHDOG will cause the software watchdog to be enabled even if a hardware watchdog is configured. 20171215: r326887 fixes the issue described in the 20171214 UPDATING entry. r326888 flips the switch back to building GELI support always. 20171214: r362593 broke ZFS + GELI support for reasons unknown. However, it also broke ZFS support generally, so GELI has been turned off by default as the lesser evil in r326857. If you boot off ZFS and/or GELI, it might not be a good time to update. 20171125: PowerPC users must update loader(8) by rebuilding world before installing a new kernel, as the protocol connecting them has changed. Without the update, loader metadata will not be passed successfully to the kernel and users will have to enter their root partition at the kernel mountroot prompt to continue booting. Newer versions of loader can boot old kernels without issue. 20171110: The LOADER_FIREWIRE_SUPPORT build variable as been renamed to WITH/OUT_LOADER_FIREWIRE. LOADER_{NO_,}GELI_SUPPORT has been renamed to WITH/OUT_LOADER_GELI. 20171106: The naive and non-compliant support of posix_fallocate(2) in ZFS has been removed as of r325320. The system call now returns EINVAL when used on a ZFS file. Although the new behavior complies with the standard, some consumers are not prepared to cope with it. One known victim is lld prior to r325420. 20171102: Building in a FreeBSD src checkout will automatically create object directories now rather than store files in the current directory if 'make obj' was not ran. Calling 'make obj' is no longer necessary. This feature can be disabled by setting WITHOUT_AUTO_OBJ=yes in /etc/src-env.conf (not /etc/src.conf), or passing the option in the environment. 20171101: The default MAKEOBJDIR has changed from /usr/obj/ for native builds, and /usr/obj// for cross-builds, to a unified /usr/obj//. This behavior can be changed to the old format by setting WITHOUT_UNIFIED_OBJDIR=yes in /etc/src-env.conf, the environment, or with -DWITHOUT_UNIFIED_OBJDIR when building. The UNIFIED_OBJDIR option is a transitional feature that will be removed for 12.0 release; please migrate to the new format for any tools by looking up the OBJDIR used by 'make -V .OBJDIR' means rather than hardcoding paths. 20171028: The native-xtools target no longer installs the files by default to the OBJDIR. Use the native-xtools-install target with a DESTDIR to install to ${DESTDIR}/${NXTP} where NXTP defaults to /nxb-bin. 20171021: As part of the boot loader infrastructure cleanup, LOADER_*_SUPPORT options are changing from controlling the build if defined / undefined to controlling the build with explicit 'yes' or 'no' values. They will shift to WITH/WITHOUT options to match other options in the system. 20171010: libstand has turned into a private library for sys/boot use only. It is no longer supported as a public interface outside of sys/boot. 20171005: The arm port has split armv6 into armv6 and armv7. armv7 is now a valid TARGET_ARCH/MACHINE_ARCH setting. If you have an armv7 system and are running a kernel from before r324363, you will need to add MACHINE_ARCH=armv7 to 'make buildworld' to do a native build. 20171003: When building multiple kernels using KERNCONF, non-existent KERNCONF files will produce an error and buildkernel will fail. Previously missing KERNCONF files silently failed giving no indication as to why, only to subsequently discover during installkernel that the desired kernel was never built in the first place. 20170912: The default serial number format for CTL LUNs has changed. This will affect users who use /dev/diskid/* device nodes, or whose FibreChannel or iSCSI clients care about their LUNs' serial numbers. Users who require serial number stability should hardcode serial numbers in /etc/ctl.conf . 20170912: For 32-bit arm compiled for hard-float support, soft-floating point binaries now always get their shared libraries from LD_SOFT_LIBRARY_PATH (in the past, this was only used if /usr/libsoft also existed). Only users with a hard-float ld.so, but soft-float everything else should be affected. 20170826: The geli password typed at boot is now hidden. To restore the previous behavior, see geli(8) for configuration options. 20170825: Move PMTUD blackhole counters to TCPSTATS and remove them from bare sysctl values. Minor nit, but requires a rebuild of both world/kernel to complete. 20170814: "make check" behavior (made in ^/head@r295380) has been changed to execute from a limited sandbox, as opposed to executing from ${TESTSDIR}. Behavioral changes: - The "beforecheck" and "aftercheck" targets are now specified. - ${CHECKDIR} (added in commit noted above) has been removed. - Legacy behavior can be enabled by setting WITHOUT_MAKE_CHECK_USE_SANDBOX in src.conf(5) or the environment. If the limited sandbox mode is enabled, "make check" will execute "make distribution", then install, execute the tests, and clean up the sandbox if successful. The "make distribution" and "make install" targets are typically run as root to set appropriate permissions and ownership at installation time. The end-user should set "WITH_INSTALL_AS_USER" in src.conf(5) or the environment if executing "make check" with limited sandbox mode using an unprivileged user. 20170808: Since the switch to GPT disk labels, fsck for UFS/FFS has been unable to automatically find alternate superblocks. As of r322297, the information needed to find alternate superblocks has been moved to the end of the area reserved for the boot block. Filesystems created with a newfs of this vintage or later will create the recovery information. If you have a filesystem created prior to this change and wish to have a recovery block created for your filesystem, you can do so by running fsck in foreground mode (i.e., do not use the -p or -y options). As it starts, fsck will ask ``SAVE DATA TO FIND ALTERNATE SUPERBLOCKS'' to which you should answer yes. 20170728: As of r321665, an NFSv4 server configuration that services Kerberos mounts or clients that do not support the uid/gid in owner/owner_group string capability, must explicitly enable the nfsuserd daemon by adding nfsuserd_enable="YES" to the machine's /etc/rc.conf file. 20170722: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 5.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170701: WITHOUT_RCMDS is now the default. Set WITH_RCMDS if you need the r-commands (rlogin, rsh, etc.) to be built with the base system. 20170625: The FreeBSD/powerpc platform now uses a 64-bit type for time_t. This is a very major ABI incompatible change, so users of FreeBSD/powerpc must be careful when performing source upgrades. It is best to run 'make installworld' from an alternate root system, either a live CD/memory stick, or a temporary root partition. Additionally, all ports must be recompiled. powerpc64 is largely unaffected, except in the case of 32-bit compatibility. All 32-bit binaries will be affected. 20170623: Forward compatibility for the "ino64" project have been committed. This will allow most new binaries to run on older kernels in a limited fashion. This prevents many of the common foot-shooting actions in the upgrade as well as the limited ability to roll back the kernel across the ino64 upgrade. Complicated use cases may not work properly, though enough simpler ones work to allow recovery in most situations. 20170620: Switch back to the BSDL dtc (Device Tree Compiler). Set WITH_GPL_DTC if you require the GPL compiler. 20170618: The internal ABI used for communication between the NFS kernel modules was changed by r320085, so __FreeBSD_version was bumped to ensure all the NFS related modules are updated together. 20170617: The ABI of struct event was changed by extending the data member to 64bit and adding ext fields. For upgrade, same precautions as for the entry 20170523 "ino64" must be followed. 20170531: The GNU roff toolchain has been removed from base. To render manpages which are not supported by mandoc(1), man(1) can fallback on GNU roff from ports (and recommends to install it). To render roff(7) documents, consider using GNU roff from ports or the heirloom doctools roff toolchain from ports via pkg install groff or via pkg install heirloom-doctools. 20170524: The ath(4) and ath_hal(4) modules now build piecemeal to allow for smaller runtime footprint builds. This is useful for embedded systems which only require one chipset support. If you load it as a module, make sure this is in /boot/loader.conf: if_ath_load="YES" This will load the HAL, all chip/RF backends and if_ath_pci. If you have if_ath_pci in /boot/loader.conf, ensure it is after if_ath or it will not load any HAL chipset support. If you want to selectively load things (eg on ye cheape ARM/MIPS platforms where RAM is at a premium) you should: * load ath_hal * load the chip modules in question * load ath_rate, ath_dfs * load ath_main * load if_ath_pci and/or if_ath_ahb depending upon your particular bus bind type - this is where probe/attach is done. For further comments/feedback, poke adrian@ . 20170523: The "ino64" 64-bit inode project has been committed, which extends a number of types to 64 bits. Upgrading in place requires care and adherence to the documented upgrade procedure. If using a custom kernel configuration ensure that the COMPAT_FREEBSD11 option is included (as during the upgrade the system will be running the ino64 kernel with the existing world). For the safest in-place upgrade begin by removing previous build artifacts via "rm -rf /usr/obj/*". Then, carefully follow the full procedure documented below under the heading "To rebuild everything and install it on the current system." Specifically, a reboot is required after installing the new kernel before installing world. 20170424: The NATM framework including the en(4), fatm(4), hatm(4), and patm(4) devices has been removed. Consumers should plan a migration before the end-of-life date for FreeBSD 11. 20170420: GNU diff has been replaced by a BSD licensed diff. Some features of GNU diff has not been implemented, if those are needed a newer version of GNU diff is available via the diffutils package under the gdiff name. 20170413: As of r316810 for ipfilter, keep frags is no longer assumed when keep state is specified in a rule. r316810 aligns ipfilter with documentation in man pages separating keep frags from keep state. This allows keep state to be specified without forcing keep frags and allows keep frags to be specified independently of keep state. To maintain previous behaviour, also specify keep frags with keep state (as documented in ipf.conf.5). 20170407: arm64 builds now use the base system LLD 4.0.0 linker by default, instead of requiring that the aarch64-binutils port or package be installed. To continue using aarch64-binutils, set CROSS_BINUTILS_PREFIX=/usr/local/aarch64-freebsd/bin . 20170405: The UDP optimization in entry 20160818 that added the sysctl net.inet.udp.require_l2_bcast has been reverted. L2 broadcast packets will no longer be treated as L3 broadcast packets. 20170331: Binds and sends to the loopback addresses, IPv6 and IPv4, will now use any explicitly assigned loopback address available in the jail instead of using the first assigned address of the jail. 20170329: The ctl.ko module no longer implements the iSCSI target frontend: cfiscsi.ko does instead. If building cfiscsi.ko as a kernel module, the module can be loaded via one of the following methods: - `cfiscsi_load="YES"` in loader.conf(5). - Add `cfiscsi` to `$kld_list` in rc.conf(5). - ctladm(8)/ctld(8), when compiled with iSCSI support (`WITH_ISCSI=yes` in src.conf(5)) Please see cfiscsi(4) for more details. 20170316: The mmcsd.ko module now additionally depends on geom_flashmap.ko. Also, mmc.ko and mmcsd.ko need to be a matching pair built from the same source (previously, the dependency of mmcsd.ko on mmc.ko was missing, but mmcsd.ko now will refuse to load if it is incompatible with mmc.ko). 20170315: The syntax of ipfw(8) named states was changed to avoid ambiguity. If you have used named states in the firewall rules, you need to modify them after installworld and before rebooting. Now named states must be prefixed with colon. 20170311: The old drm (sys/dev/drm/) drivers for i915 and radeon have been removed as the userland we provide cannot use them. The KMS version (sys/dev/drm2) supports the same hardware. 20170302: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 4.0.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20170221: The code that provides support for ZFS .zfs/ directory functionality has been reimplemented. It's not possible now to create a snapshot by mkdir under .zfs/snapshot/. That should be the only user visible change. 20170216: EISA bus support has been removed. The WITH_EISA option is no longer valid. 20170215: MCA bus support has been removed. 20170127: The WITH_LLD_AS_LD / WITHOUT_LLD_AS_LD build knobs have been renamed WITH_LLD_IS_LD / WITHOUT_LLD_IS_LD, for consistency with CLANG_IS_CC. 20170112: The EM_MULTIQUEUE kernel configuration option is deprecated now that the em(4) driver conforms to iflib specifications. 20170109: The igb(4), em(4) and lem(4) ethernet drivers are now implemented via IFLIB. If you have a custom kernel configuration that excludes em(4) but you use igb(4), you need to re-add em(4) to your custom configuration. 20161217: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.1. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161124: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.9.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20161119: The layout of the pmap structure has changed for powerpc to put the pmap statistics at the front for all CPU variations. libkvm(3) and all tools that link against it need to be recompiled. 20161030: isl(4) and cyapa(4) drivers now require a new driver, chromebook_platform(4), to work properly on Chromebook-class hardware. On other types of hardware the drivers may need to be configured using device hints. Please see the corresponding manual pages for details. 20161017: The urtwn(4) driver was merged into rtwn(4) and now consists of rtwn(4) main module + rtwn_usb(4) and rtwn_pci(4) bus-specific parts. Also, firmware for RTL8188CE was renamed due to possible name conflict (rtwnrtl8192cU(B) -> rtwnrtl8192cE(B)) 20161015: GNU rcs has been removed from base. It is available as packages: - rcs: Latest GPLv3 GNU rcs version. - rcs57: Copy of the latest version of GNU rcs (GPLv2) before it was removed from base. 20161008: Use of the cc_cdg, cc_chd, cc_hd, or cc_vegas congestion control modules now requires that the kernel configuration contain the TCP_HHOOK option. (This option is included in the GENERIC kernel.) 20161003: The WITHOUT_ELFCOPY_AS_OBJCOPY src.conf(5) knob has been retired. ELF Tool Chain's elfcopy is always installed as /usr/bin/objcopy. 20160924: Relocatable object files with the extension of .So have been renamed to use an extension of .pico instead. The purpose of this change is to avoid a name clash with shared libraries on case-insensitive file systems. On those file systems, foo.So is the same file as foo.so. 20160918: GNU rcs has been turned off by default. It can (temporarily) be built again by adding WITH_RCS knob in src.conf. Otherwise, GNU rcs is available from packages: - rcs: Latest GPLv3 GNU rcs version. - rcs57: Copy of the latest version of GNU rcs (GPLv2) from base. 20160918: The backup_uses_rcs functionality has been removed from rc.subr. 20160908: The queue(3) debugging macro, QUEUE_MACRO_DEBUG, has been split into two separate components, QUEUE_MACRO_DEBUG_TRACE and QUEUE_MACRO_DEBUG_TRASH. Define both for the original QUEUE_MACRO_DEBUG behavior. 20160824: r304787 changed some ioctl interfaces between the iSCSI userspace programs and the kernel. ctladm, ctld, iscsictl, and iscsid must be rebuilt to work with new kernels. __FreeBSD_version has been bumped to 1200005. 20160818: The UDP receive code has been updated to only treat incoming UDP packets that were addressed to an L2 broadcast address as L3 broadcast packets. It is not expected that this will affect any standards-conforming UDP application. The new behaviour can be disabled by setting the sysctl net.inet.udp.require_l2_bcast to 0. 20160818: Remove the openbsd_poll system call. __FreeBSD_version has been bumped because of this. 20160708: The stable/11 branch has been created from head@r302406. 20160622: The libc stub for the pipe(2) system call has been replaced with a wrapper that calls the pipe2(2) system call and the pipe(2) system call is now only implemented by the kernels that include "options COMPAT_FREEBSD10" in their config file (this is the default). Users should ensure that this option is enabled in their kernel or upgrade userspace to r302092 before upgrading their kernel. 20160527: CAM will now strip leading spaces from SCSI disks' serial numbers. This will affect users who create UFS filesystems on SCSI disks using those disk's diskid device nodes. For example, if /etc/fstab previously contained a line like "/dev/diskid/DISK-%20%20%20%20%20%20%20ABCDEFG0123456", you should change it to "/dev/diskid/DISK-ABCDEFG0123456". Users of geom transforms like gmirror may also be affected. ZFS users should generally be fine. 20160523: The bitstring(3) API has been updated with new functionality and improved performance. But it is binary-incompatible with the old API. Objects built with the new headers may not be linked against objects built with the old headers. 20160520: The brk and sbrk functions have been removed from libc on arm64. Binutils from ports has been updated to not link to these functions and should be updated to the latest version before installing a new libc. 20160517: The armv6 port now defaults to hard float ABI. Limited support for running both hardfloat and soft float on the same system is available using the libraries installed with -DWITH_LIBSOFT. This has only been tested as an upgrade path for installworld and packages may fail or need manual intervention to run. New packages will be needed. To update an existing self-hosted armv6hf system, you must add TARGET_ARCH=armv6 on the make command line for both the build and the install steps. 20160510: Kernel modules compiled outside of a kernel build now default to installing to /boot/modules instead of /boot/kernel. Many kernel modules built this way (such as those in ports) already overrode KMODDIR explicitly to install into /boot/modules. However, manually building and installing a module from /sys/modules will now install to /boot/modules instead of /boot/kernel. 20160414: The CAM I/O scheduler has been committed to the kernel. There should be no user visible impact. This does enable NCQ Trim on ada SSDs. While the list of known rogues that claim support for this but actually corrupt data is believed to be complete, be on the lookout for data corruption. The known rogue list is believed to be complete: o Crucial MX100, M550 drives with MU01 firmware. o Micron M510 and M550 drives with MU01 firmware. o Micron M500 prior to MU07 firmware o Samsung 830, 840, and 850 all firmwares o FCCT M500 all firmwares Crucial has firmware http://www.crucial.com/usa/en/support-ssd-firmware with working NCQ TRIM. For Micron branded drives, see your sales rep for updated firmware. Black listed drives will work correctly because these drives work correctly so long as no NCQ TRIMs are sent to them. Given this list is the same as found in Linux, it's believed there are no other rogues in the market place. All other models from the above vendors work. To be safe, if you are at all concerned, you can quirk each of your drives to prevent NCQ from being sent by setting: kern.cam.ada.X.quirks="0x2" in loader.conf. If the drive requires the 4k sector quirk, set the quirks entry to 0x3. 20160330: The FAST_DEPEND build option has been removed and its functionality is now the one true way. The old mkdep(1) style of 'make depend' has been removed. See 20160311 for further details. 20160317: Resource range types have grown from unsigned long to uintmax_t. All drivers, and anything using libdevinfo, need to be recompiled. 20160311: WITH_FAST_DEPEND is now enabled by default for in-tree and out-of-tree builds. It no longer runs mkdep(1) during 'make depend', and the 'make depend' stage can safely be skipped now as it is auto ran when building 'make all' and will generate all SRCS and DPSRCS before building anything else. Dependencies are gathered at compile time with -MF flags kept in separate .depend files per object file. Users should run 'make cleandepend' once if using -DNO_CLEAN to clean out older stale .depend files. 20160306: On amd64, clang 3.8.0 can now insert sections of type AMD64_UNWIND into kernel modules. Therefore, if you load any kernel modules at boot time, please install the boot loaders after you install the kernel, but before rebooting, e.g.: make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installkernel KERNCONF=YOUR_KERNEL_HERE make -C sys/boot install Then follow the usual steps, described in the General Notes section, below. 20160305: Clang, llvm, lldb and compiler-rt have been upgraded to 3.8.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20160301: The AIO subsystem is now a standard part of the kernel. The VFS_AIO kernel option and aio.ko kernel module have been removed. Due to stability concerns, asynchronous I/O requests are only permitted on sockets and raw disks by default. To enable asynchronous I/O requests on all file types, set the vfs.aio.enable_unsafe sysctl to a non-zero value. 20160226: The ELF object manipulation tool objcopy is now provided by the ELF Tool Chain project rather than by GNU binutils. It should be a drop-in replacement, with the addition of arm64 support. The (temporary) src.conf knob WITHOUT_ELFCOPY_AS_OBJCOPY knob may be set to obtain the GNU version if necessary. 20160129: Building ZFS pools on top of zvols is prohibited by default. That feature has never worked safely; it's always been prone to deadlocks. Using a zvol as the backing store for a VM guest's virtual disk will still work, even if the guest is using ZFS. Legacy behavior can be restored by setting vfs.zfs.vol.recursive=1. 20160119: The NONE and HPN patches has been removed from OpenSSH. They are still available in the security/openssh-portable port. 20160113: With the addition of ypldap(8), a new _ypldap user is now required during installworld. "mergemaster -p" can be used to add the user prior to installworld, as documented in the handbook. 20151216: The tftp loader (pxeboot) now uses the option root-path directive. As a consequence it no longer looks for a pxeboot.4th file on the tftp server. Instead it uses the regular /boot infrastructure as with the other loaders. 20151211: The code to start recording plug and play data into the modules has been committed. While the old tools will properly build a new kernel, a number of warnings about "unknown metadata record 4" will be produced for an older kldxref. To avoid such warnings, make sure to rebuild the kernel toolchain (or world). Make sure that you have r292078 or later when trying to build 292077 or later before rebuilding. 20151207: Debug data files are now built by default with 'make buildworld' and installed with 'make installworld'. This facilitates debugging but requires more disk space both during the build and for the installed world. Debug files may be disabled by setting WITHOUT_DEBUG_FILES=yes in src.conf(5). 20151130: r291527 changed the internal interface between the nfsd.ko and nfscommon.ko modules. As such, they must both be upgraded to-gether. __FreeBSD_version has been bumped because of this. 20151108: Add support for unicode collation strings leads to a change of order of files listed by ls(1) for example. To get back to the old behaviour, set LC_COLLATE environment variable to "C". Databases administrators will need to reindex their databases given collation results will be different. Due to a bug in install(1) it is recommended to remove the ancient locales before running make installworld. rm -rf /usr/share/locale/* 20151030: The OpenSSL has been upgraded to 1.0.2d. Any binaries requiring libcrypto.so.7 or libssl.so.7 must be recompiled. 20151020: Qlogic 24xx/25xx firmware images were updated from 5.5.0 to 7.3.0. Kernel modules isp_2400_multi and isp_2500_multi were removed and should be replaced with isp_2400 and isp_2500 modules respectively. 20151017: The build previously allowed using 'make -n' to not recurse into sub-directories while showing what commands would be executed, and 'make -n -n' to recursively show commands. Now 'make -n' will recurse and 'make -N' will not. 20151012: If you specify SENDMAIL_MC or SENDMAIL_CF in make.conf, mergemaster and etcupdate will now use this file. A custom sendmail.cf is now updated via this mechanism rather than via installworld. If you had excluded sendmail.cf in mergemaster.rc or etcupdate.conf, you may want to remove the exclusion or change it to "always install". /etc/mail/sendmail.cf is now managed the same way regardless of whether SENDMAIL_MC/SENDMAIL_CF is used. If you are not using SENDMAIL_MC/SENDMAIL_CF there should be no change in behavior. 20151011: Compatibility shims for legacy ATA device names have been removed. It includes ATA_STATIC_ID kernel option, kern.cam.ada.legacy_aliases and kern.geom.raid.legacy_aliases loader tunables, kern.devalias.* environment variables, /dev/ad* and /dev/ar* symbolic links. 20151006: Clang, llvm, lldb, compiler-rt and libc++ have been upgraded to 3.7.0. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using clang 3.5.0 or higher. 20150924: Kernel debug files have been moved to /usr/lib/debug/boot/kernel/, and renamed from .symbols to .debug. This reduces the size requirements on the boot partition or file system and provides consistency with userland debug files. When using the supported kernel installation method the /usr/lib/debug/boot/kernel directory will be renamed (to kernel.old) as is done with /boot/kernel. Developers wishing to maintain the historical behavior of installing debug files in /boot/kernel/ can set KERN_DEBUGDIR="" in src.conf(5). 20150827: The wireless drivers had undergone changes that remove the 'parent interface' from the ifconfig -l output. The rc.d network scripts used to check presence of a parent interface in the list, so old scripts would fail to start wireless networking. Thus, etcupdate(3) or mergemaster(8) run is required after kernel update, to update your rc.d scripts in /etc. 20150827: pf no longer supports 'scrub fragment crop' or 'scrub fragment drop-ovl' These configurations are now automatically interpreted as 'scrub fragment reassemble'. 20150817: Kernel-loadable modules for the random(4) device are back. To use them, the kernel must have device random options RANDOM_LOADABLE kldload(8) can then be used to load random_fortuna.ko or random_yarrow.ko. Please note that due to the indirect function calls that the loadable modules need to provide, the build-in variants will be slightly more efficient. The random(4) kernel option RANDOM_DUMMY has been retired due to unpopularity. It was not all that useful anyway. 20150813: The WITHOUT_ELFTOOLCHAIN_TOOLS src.conf(5) knob has been retired. Control over building the ELF Tool Chain tools is now provided by the WITHOUT_TOOLCHAIN knob. 20150810: The polarity of Pulse Per Second (PPS) capture events with the uart(4) driver has been corrected. Prior to this change the PPS "assert" event corresponded to the trailing edge of a positive PPS pulse and the "clear" event was the leading edge of the next pulse. As the width of a PPS pulse in a typical GPS receiver is on the order of 1 millisecond, most users will not notice any significant difference with this change. Anyone who has compensated for the historical polarity reversal by configuring a negative offset equal to the pulse width will need to remove that workaround. 20150809: The default group assigned to /dev/dri entries has been changed from 'wheel' to 'video' with the id of '44'. If you want to have access to the dri devices please add yourself to the video group with: # pw groupmod video -m $USER 20150806: The menu.rc and loader.rc files will now be replaced during upgrades. Please migrate local changes to menu.rc.local and loader.rc.local instead. 20150805: GNU Binutils versions of addr2line, c++filt, nm, readelf, size, strings and strip have been removed. The src.conf(5) knob WITHOUT_ELFTOOLCHAIN_TOOLS no longer provides the binutils tools. 20150728: As ZFS requires more kernel stack pages than is the default on some architectures e.g. i386, it now warns if KSTACK_PAGES is less than ZFS_MIN_KSTACK_PAGES (which is 4 at the time of writing). Please consider using 'options KSTACK_PAGES=X' where X is greater than or equal to ZFS_MIN_KSTACK_PAGES i.e. 4 in such configurations. 20150706: sendmail has been updated to 8.15.2. Starting with FreeBSD 11.0 and sendmail 8.15, sendmail uses uncompressed IPv6 addresses by default, i.e., they will not contain "::". For example, instead of ::1, it will be 0:0:0:0:0:0:0:1. This permits a zero subnet to have a more specific match, such as different map entries for IPv6:0:0 vs IPv6:0. This change requires that configuration data (including maps, files, classes, custom ruleset, etc.) must use the same format, so make certain such configuration data is upgrading. As a very simple check search for patterns like 'IPv6:[0-9a-fA-F:]*::' and 'IPv6::'. To return to the old behavior, set the m4 option confUSE_COMPRESSED_IPV6_ADDRESSES or the cf option UseCompressedIPv6Addresses. 20150630: The default kernel entropy-processing algorithm is now Fortuna, replacing Yarrow. Assuming you have 'device random' in your kernel config file, the configurations allow a kernel option to override this default. You may choose *ONE* of: options RANDOM_YARROW # Legacy /dev/random algorithm. options RANDOM_DUMMY # Blocking-only driver. If you have neither, you get Fortuna. For most people, read no further, Fortuna will give a /dev/random that works like it always used to, and the difference will be irrelevant. If you remove 'device random', you get *NO* kernel-processed entropy at all. This may be acceptable to folks building embedded systems, but has complications. Carry on reading, and it is assumed you know what you need. *PLEASE* read random(4) and random(9) if you are in the habit of tweaking kernel configs, and/or if you are a member of the embedded community, wanting specific and not-usual behaviour from your security subsystems. NOTE!! If you use RANDOM_DUMMY and/or have no 'device random', you will NOT have a functioning /dev/random, and many cryptographic features will not work, including SSH. You may also find strange behaviour from the random(3) set of library functions, in particular sranddev(3), srandomdev(3) and arc4random(3). The reason for this is that the KERN_ARND sysctl only returns entropy if it thinks it has some to share, and with RANDOM_DUMMY or no 'device random' this will never happen. 20150623: An additional fix for the issue described in the 20150614 sendmail entry below has been committed in revision 284717. 20150616: FreeBSD's old make (fmake) has been removed from the system. It is available as the devel/fmake port or via pkg install fmake. 20150615: The fix for the issue described in the 20150614 sendmail entry below has been committed in revision 284436. The work around described in that entry is no longer needed unless the default setting is overridden by a confDH_PARAMETERS configuration setting of '5' or pointing to a 512 bit DH parameter file. 20150614: ALLOW_DEPRECATED_ATF_TOOLS/ATFFILE support has been removed from atf.test.mk (included from bsd.test.mk). Please upgrade devel/atf and devel/kyua to version 0.20+ and adjust any calling code to work with Kyuafile and kyua. 20150614: The import of openssl to address the FreeBSD-SA-15:10.openssl security advisory includes a change which rejects handshakes with DH parameters below 768 bits. sendmail releases prior to 8.15.2 (not yet released), defaulted to a 512 bit DH parameter setting for client connections. To work around this interoperability, sendmail can be configured to use a 2048 bit DH parameter by: 1. Edit /etc/mail/`hostname`.mc 2. If a setting for confDH_PARAMETERS does not exist or exists and is set to a string beginning with '5', replace it with '2'. 3. If a setting for confDH_PARAMETERS exists and is set to a file path, create a new file with: openssl dhparam -out /path/to/file 2048 4. Rebuild the .cf file: cd /etc/mail/; make; make install 5. Restart sendmail: cd /etc/mail/; make restart A sendmail patch is coming, at which time this file will be updated. 20150604: Generation of legacy formatted entries have been disabled by default in pwd_mkdb(8), as all base system consumers of the legacy formatted entries were converted to use the new format by default when the new, machine independent format have been added and supported since FreeBSD 5.x. Please see the pwd_mkdb(8) manual page for further details. 20150525: Clang and llvm have been upgraded to 3.6.1 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150521: TI platform code switched to using vendor DTS files and this update may break existing systems running on Beaglebone, Beaglebone Black, and Pandaboard: - dtb files should be regenerated/reinstalled. Filenames are the same but content is different now - GPIO addressing was changed, now each GPIO bank (32 pins per bank) has its own /dev/gpiocX device, e.g. pin 121 on /dev/gpioc0 in old addressing scheme is now pin 25 on /dev/gpioc3. - Pandaboard: /etc/ttys should be updated, serial console device is now /dev/ttyu2, not /dev/ttyu0 20150501: soelim(1) from gnu/usr.bin/groff has been replaced by usr.bin/soelim. If you need the GNU extension from groff soelim(1), install groff from package: pkg install groff, or via ports: textproc/groff. 20150423: chmod, chflags, chown and chgrp now affect symlinks in -R mode as defined in symlink(7); previously symlinks were silently ignored. 20150415: The const qualifier has been removed from iconv(3) to comply with POSIX. The ports tree is aware of this from r384038 onwards. 20150416: Libraries specified by LIBADD in Makefiles must have a corresponding DPADD_ variable to ensure correct dependencies. This is now enforced in src.libnames.mk. 20150324: From legacy ata(4) driver was removed support for SATA controllers supported by more functional drivers ahci(4), siis(4) and mvs(4). Kernel modules ataahci and ataadaptec were removed completely, replaced by ahci and mvs modules respectively. 20150315: Clang, llvm and lldb have been upgraded to 3.6.0 release. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0 or higher. 20150307: The 32-bit PowerPC kernel has been changed to a position-independent executable. This can only be booted with a version of loader(8) newer than January 31, 2015, so make sure to update both world and kernel before rebooting. 20150217: If you are running a -CURRENT kernel since r273872 (Oct 30th, 2014), but before r278950, the RNG was not seeded properly. Immediately upgrade the kernel to r278950 or later and regenerate any keys (e.g. ssh keys or openssl keys) that were generated w/ a kernel from that range. This does not affect programs that directly used /dev/random or /dev/urandom. All userland uses of arc4random(3) are affected. 20150210: The autofs(4) ABI was changed in order to restore binary compatibility with 10.1-RELEASE. The automountd(8) daemon needs to be rebuilt to work with the new kernel. 20150131: The powerpc64 kernel has been changed to a position-independent executable. This can only be booted with a new version of loader(8), so make sure to update both world and kernel before rebooting. 20150118: Clang and llvm have been upgraded to 3.5.1 release. This is a bugfix only release, no new features have been added. Please see the 20141231 entry below for information about prerequisites and upgrading, if you are not already using 3.5.0. 20150107: ELF tools addr2line, elfcopy (strip), nm, size, and strings are now taken from the ELF Tool Chain project rather than GNU binutils. They should be drop-in replacements, with the addition of arm64 support. The WITHOUT_ELFTOOLCHAIN_TOOLS= knob may be used to obtain the binutils tools, if necessary. See 20150805 for updated information. 20150105: The default Unbound configuration now enables remote control using a local socket. Users who have already enabled the local_unbound service should regenerate their configuration by running "service local_unbound setup" as root. 20150102: The GNU texinfo and GNU info pages have been removed. To be able to view GNU info pages please install texinfo from ports. 20141231: Clang, llvm and lldb have been upgraded to 3.5.0 release. As of this release, a prerequisite for building clang, llvm and lldb is a C++11 capable compiler and C++11 standard library. This means that to be able to successfully build the cross-tools stage of buildworld, with clang as the bootstrap compiler, your system compiler or cross compiler should either be clang 3.3 or later, or gcc 4.8 or later, and your system C++ library should be libc++, or libdstdc++ from gcc 4.8 or later. On any standard FreeBSD 10.x or 11.x installation, where clang and libc++ are on by default (that is, on x86 or arm), this should work out of the box. On 9.x installations where clang is enabled by default, e.g. on x86 and powerpc, libc++ will not be enabled by default, so libc++ should be built (with clang) and installed first. If both clang and libc++ are missing, build clang first, then use it to build libc++. On 8.x and earlier installations, upgrade to 9.x first, and then follow the instructions for 9.x above. Sparc64 and mips users are unaffected, as they still use gcc 4.2.1 by default, and do not build clang. Many embedded systems are resource constrained, and will not be able to build clang in a reasonable time, or in some cases at all. In those cases, cross building bootable systems on amd64 is a workaround. This new version of clang introduces a number of new warnings, of which the following are most likely to appear: -Wabsolute-value This warns in two cases, for both C and C++: * When the code is trying to take the absolute value of an unsigned quantity, which is effectively a no-op, and almost never what was intended. The code should be fixed, if at all possible. If you are sure that the unsigned quantity can be safely cast to signed, without loss of information or undefined behavior, you can add an explicit cast, or disable the warning. * When the code is trying to take an absolute value, but the called abs() variant is for the wrong type, which can lead to truncation. If you want to disable the warning instead of fixing the code, please make sure that truncation will not occur, or it might lead to unwanted side-effects. -Wtautological-undefined-compare and -Wundefined-bool-conversion These warn when C++ code is trying to compare 'this' against NULL, while 'this' should never be NULL in well-defined C++ code. However, there is some legacy (pre C++11) code out there, which actively abuses this feature, which was less strictly defined in previous C++ versions. Squid and openjdk do this, for example. The warning can be turned off for C++98 and earlier, but compiling the code in C++11 mode might result in unexpected behavior; for example, the parts of the program that are unreachable could be optimized away. 20141222: The old NFS client and server (kernel options NFSCLIENT, NFSSERVER) kernel sources have been removed. The .h files remain, since some utilities include them. This will need to be fixed later. If "mount -t oldnfs ..." is attempted, it will fail. If the "-o" option on mountd(8), nfsd(8) or nfsstat(1) is used, the utilities will report errors. 20141121: The handling of LOCAL_LIB_DIRS has been altered to skip addition of directories to top level SUBDIR variable when their parent directory is included in LOCAL_DIRS. Users with build systems with such hierarchies and without SUBDIR entries in the parent directory Makefiles should add them or add the directories to LOCAL_DIRS. 20141109: faith(4) and faithd(8) have been removed from the base system. Faith has been obsolete for a very long time. 20141104: vt(4), the new console driver, is enabled by default. It brings support for Unicode and double-width characters, as well as support for UEFI and integration with the KMS kernel video drivers. You may need to update your console settings in /etc/rc.conf, most probably the keymap. During boot, /etc/rc.d/syscons will indicate what you need to do. vt(4) still has issues and lacks some features compared to syscons(4). See the wiki for up-to-date information: https://wiki.freebsd.org/Newcons If you want to keep using syscons(4), you can do so by adding the following line to /boot/loader.conf: kern.vty=sc 20141102: pjdfstest has been integrated into kyua as an opt-in test suite. Please see share/doc/pjdfstest/README for more details on how to execute it. 20141009: gperf has been removed from the base system for architectures that use clang. Ports that require gperf will obtain it from the devel/gperf port. 20140923: pjdfstest has been moved from tools/regression/pjdfstest to contrib/pjdfstest . 20140922: At svn r271982, The default linux compat kernel ABI has been adjusted to 2.6.18 in support of the linux-c6 compat ports infrastructure update. If you wish to continue using the linux-f10 compat ports, add compat.linux.osrelease=2.6.16 to your local sysctl.conf. Users are encouraged to update their linux-compat packages to linux-c6 during their next update cycle. 20140729: The ofwfb driver, used to provide a graphics console on PowerPC when using vt(4), no longer allows mmap() of all physical memory. This will prevent Xorg on PowerPC with some ATI graphics cards from initializing properly unless x11-servers/xorg-server is updated to 1.12.4_8 or newer. 20140723: The xdev targets have been converted to using TARGET and TARGET_ARCH instead of XDEV and XDEV_ARCH. 20140719: The default unbound configuration has been modified to address issues with reverse lookups on networks that use private address ranges. If you use the local_unbound service, run "service local_unbound setup" as root to regenerate your configuration, then "service local_unbound reload" to load the new configuration. 20140709: The GNU texinfo and GNU info pages are not built and installed anymore, WITH_INFO knob has been added to allow to built and install them again. UPDATE: see 20150102 entry on texinfo's removal 20140708: The GNU readline library is now an INTERNALLIB - that is, it is statically linked into consumers (GDB and variants) in the base system, and the shared library is no longer installed. The devel/readline port is available for third party software that requires readline. 20140702: The Itanium architecture (ia64) has been removed from the list of known architectures. This is the first step in the removal of the architecture. 20140701: Commit r268115 has added NFSv4.1 server support, merged from projects/nfsv4.1-server. Since this includes changes to the internal interfaces between the NFS related modules, a full build of the kernel and modules will be necessary. __FreeBSD_version has been bumped. 20140629: The WITHOUT_VT_SUPPORT kernel config knob has been renamed WITHOUT_VT. (The other _SUPPORT knobs have a consistent meaning which differs from the behaviour controlled by this knob.) 20140619: Maximal length of the serial number in CTL was increased from 16 to 64 chars, that breaks ABI. All CTL-related tools, such as ctladm and ctld, need to be rebuilt to work with a new kernel. 20140606: The libatf-c and libatf-c++ major versions were downgraded to 0 and 1 respectively to match the upstream numbers. They were out of sync because, when they were originally added to FreeBSD, the upstream versions were not respected. These libraries are private and not yet built by default, so renumbering them should be a non-issue. However, unclean source trees will yield broken test programs once the operator executes "make delete-old-libs" after a "make installworld". Additionally, the atf-sh binary was made private by moving it into /usr/libexec/. Already-built shell test programs will keep the path to the old binary so they will break after "make delete-old" is run. If you are using WITH_TESTS=yes (not the default), wipe the object tree and rebuild from scratch to prevent spurious test failures. This is only needed once: the misnumbered libraries and misplaced binaries have been added to OptionalObsoleteFiles.inc so they will be removed during a clean upgrade. 20140512: Clang and llvm have been upgraded to 3.4.1 release. 20140508: We bogusly installed src.opts.mk in /usr/share/mk. This file should be removed to avoid issues in the future (and has been added to ObsoleteFiles.inc). 20140505: /etc/src.conf now affects only builds of the FreeBSD src tree. In the past, it affected all builds that used the bsd.*.mk files. The old behavior was a bug, but people may have relied upon it. To get this behavior back, you can .include /etc/src.conf from /etc/make.conf (which is still global and isn't changed). This also changes the behavior of incremental builds inside the tree of individual directories. Set MAKESYSPATH to ".../share/mk" to do that. Although this has survived make universe and some upgrade scenarios, other upgrade scenarios may have broken. At least one form of temporary breakage was fixed with MAKESYSPATH settings for buildworld as well... In cases where MAKESYSPATH isn't working with this setting, you'll need to set it to the full path to your tree. One side effect of all this cleaning up is that bsd.compiler.mk is no longer implicitly included by bsd.own.mk. If you wish to use COMPILER_TYPE, you must now explicitly include bsd.compiler.mk as well. 20140430: The lindev device has been removed since /dev/full has been made a standard device. __FreeBSD_version has been bumped. 20140424: The knob WITHOUT_VI was added to the base system, which controls building ex(1), vi(1), etc. Older releases of FreeBSD required ex(1) in order to reorder files share/termcap and didn't build ex(1) as a build tool, so building/installing with WITH_VI is highly advised for build hosts for older releases. This issue has been fixed in stable/9 and stable/10 in r277022 and r276991, respectively. 20140418: The YES_HESIOD knob has been removed. It has been obsolete for a decade. Please move to using WITH_HESIOD instead or your builds will silently lack HESIOD. 20140405: The uart(4) driver has been changed with respect to its handling of the low-level console. Previously the uart(4) driver prevented any process from changing the baudrate or the CLOCAL and HUPCL control flags. By removing the restrictions, operators can make changes to the serial console port without having to reboot. However, when getty(8) is started on the serial device that is associated with the low-level console, a misconfigured terminal line in /etc/ttys will now have a real impact. Before upgrading the kernel, make sure that /etc/ttys has the serial console device configured as 3wire without baudrate to preserve the previous behaviour. E.g: ttyu0 "/usr/libexec/getty 3wire" vt100 on secure 20140306: Support for libwrap (TCP wrappers) in rpcbind was disabled by default to improve performance. To re-enable it, if needed, run rpcbind with command line option -W. 20140226: Switched back to the GPL dtc compiler due to updates in the upstream dts files not being supported by the BSDL dtc compiler. You will need to rebuild your kernel toolchain to pick up the new compiler. Core dumps may result while building dtb files during a kernel build if you fail to do so. Set WITHOUT_GPL_DTC if you require the BSDL compiler. 20140216: Clang and llvm have been upgraded to 3.4 release. 20140216: The nve(4) driver has been removed. Please use the nfe(4) driver for NVIDIA nForce MCP Ethernet adapters instead. 20140212: An ABI incompatibility crept into the libc++ 3.4 import in r261283. This could cause certain C++ applications using shared libraries built against the previous version of libc++ to crash. The incompatibility has now been fixed, but any C++ applications or shared libraries built between r261283 and r261801 should be recompiled. 20140204: OpenSSH will now ignore errors caused by kernel lacking of Capsicum capability mode support. Please note that enabling the feature in kernel is still highly recommended. 20140131: OpenSSH is now built with sandbox support, and will use sandbox as the default privilege separation method. This requires Capsicum capability mode support in kernel. 20140128: The libelf and libdwarf libraries have been updated to newer versions from upstream. Shared library version numbers for these two libraries were bumped. Any ports or binaries requiring these two libraries should be recompiled. __FreeBSD_version is bumped to 1100006. 20140110: If a Makefile in a tests/ directory was auto-generating a Kyuafile instead of providing an explicit one, this would prevent such Makefile from providing its own Kyuafile in the future during NO_CLEAN builds. This has been fixed in the Makefiles but manual intervention is needed to clean an objdir if you use NO_CLEAN: # find /usr/obj -name Kyuafile | xargs rm -f 20131213: The behavior of gss_pseudo_random() for the krb5 mechanism has changed, for applications requesting a longer random string than produced by the underlying enctype's pseudo-random() function. In particular, the random string produced from a session key of enctype aes256-cts-hmac-sha1-96 or aes256-cts-hmac-sha1-96 will be different at the 17th octet and later, after this change. The counter used in the PRF+ construction is now encoded as a big-endian integer in accordance with RFC 4402. __FreeBSD_version is bumped to 1100004. 20131108: The WITHOUT_ATF build knob has been removed and its functionality has been subsumed into the more generic WITHOUT_TESTS. If you were using the former to disable the build of the ATF libraries, you should change your settings to use the latter. 20131025: The default version of mtree is nmtree which is obtained from NetBSD. The output is generally the same, but may vary slightly. If you found you need identical output adding "-F freebsd9" to the command line should do the trick. For the time being, the old mtree is available as fmtree. 20131014: libbsdyml has been renamed to libyaml and moved to /usr/lib/private. This will break ports-mgmt/pkg. Rebuild the port, or upgrade to pkg 1.1.4_8 and verify bsdyml not linked in, before running "make delete-old-libs": # make -C /usr/ports/ports-mgmt/pkg build deinstall install clean or # pkg install pkg; ldd /usr/local/sbin/pkg | grep bsdyml 20131010: The stable/10 branch has been created in subversion from head revision r256279. COMMON ITEMS: General Notes ------------- Avoid using make -j when upgrading. While generally safe, there are sometimes problems using -j to upgrade. If your upgrade fails with -j, please try again without -j. From time to time in the past there have been problems using -j with buildworld and/or installworld. This is especially true when upgrading between "distant" versions (eg one that cross a major release boundary or several minor releases, or when several months have passed on the -current branch). Sometimes, obscure build problems are the result of environment poisoning. This can happen because the make utility reads its environment when searching for values for global variables. To run your build attempts in an "environmental clean room", prefix all make commands with 'env -i '. See the env(1) manual page for more details. When upgrading from one major version to another it is generally best to upgrade to the latest code in the currently installed branch first, then do an upgrade to the new branch. This is the best-tested upgrade path, and has the highest probability of being successful. Please try this approach if you encounter problems with a major version upgrade. Since the stable 4.x branch point, one has generally been able to upgrade from anywhere in the most recent stable branch to head / current (or even the last couple of stable branches). See the top of this file when there's an exception. When upgrading a live system, having a root shell around before installing anything can help undo problems. Not having a root shell around can lead to problems if pam has changed too much from your starting point to allow continued authentication after the upgrade. This file should be read as a log of events. When a later event changes information of a prior event, the prior event should not be deleted. Instead, a pointer to the entry with the new information should be placed in the old entry. Readers of this file should also sanity check older entries before relying on them blindly. Authors of new entries should write them with this in mind. ZFS notes --------- When upgrading the boot ZFS pool to a new version, always follow these two steps: 1.) recompile and reinstall the ZFS boot loader and boot block (this is part of "make buildworld" and "make installworld") 2.) update the ZFS boot block on your boot drive The following example updates the ZFS boot block on the first partition (freebsd-boot) of a GPT partitioned drive ada0: "gpart bootcode -p /boot/gptzfsboot -i 1 ada0" Non-boot pools do not need these updates. To build a kernel ----------------- If you are updating from a prior version of FreeBSD (even one just a few days old), you should follow this procedure. It is the most failsafe as it uses a /usr/obj tree with a fresh mini-buildworld, make kernel-toolchain make -DALWAYS_CHECK_MAKE buildkernel KERNCONF=YOUR_KERNEL_HERE make -DALWAYS_CHECK_MAKE installkernel KERNCONF=YOUR_KERNEL_HERE To test a kernel once --------------------- If you just want to boot a kernel once (because you are not sure if it works, or if you want to boot a known bad kernel to provide debugging information) run make installkernel KERNCONF=YOUR_KERNEL_HERE KODIR=/boot/testkernel nextboot -k testkernel To rebuild everything and install it on the current system. ----------------------------------------------------------- # Note: sometimes if you are running current you gotta do more than # is listed here if you are upgrading from a really old current. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installkernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] To cross-install current onto a separate partition -------------------------------------------------- # In this approach we use a separate partition to hold # current's root, 'usr', and 'var' directories. A partition # holding "/", "/usr" and "/var" should be about 2GB in # size. make buildworld make buildkernel KERNCONF=YOUR_KERNEL_HERE make installworld DESTDIR=${CURRENT_ROOT} -DDB_FROM_SRC make distribution DESTDIR=${CURRENT_ROOT} # if newfs'd make installkernel KERNCONF=YOUR_KERNEL_HERE DESTDIR=${CURRENT_ROOT} cp /etc/fstab ${CURRENT_ROOT}/etc/fstab # if newfs'd To upgrade in-place from stable to current ---------------------------------------------- make buildworld [9] make buildkernel KERNCONF=YOUR_KERNEL_HERE [8] make installkernel KERNCONF=YOUR_KERNEL_HERE [1] [3] mergemaster -Fp [5] make installworld mergemaster -Fi [4] make delete-old [6] Make sure that you've read the UPDATING file to understand the tweaks to various things you need. At this point in the life cycle of current, things change often and you are on your own to cope. The defaults can also change, so please read ALL of the UPDATING entries. Also, if you are tracking -current, you must be subscribed to freebsd-current@freebsd.org. Make sure that before you update your sources that you have read and understood all the recent messages there. If in doubt, please track -stable which has much fewer pitfalls. [1] If you have third party modules, such as vmware, you should disable them at this point so they don't crash your system on reboot. [3] From the bootblocks, boot -s, and then do fsck -p mount -u / mount -a cd src adjkerntz -i # if CMOS is wall time Also, when doing a major release upgrade, it is required that you boot into single user mode to do the installworld. [4] Note: This step is non-optional. Failure to do this step can result in a significant reduction in the functionality of the system. Attempting to do it by hand is not recommended and those that pursue this avenue should read this file carefully, as well as the archives of freebsd-current and freebsd-hackers mailing lists for potential gotchas. The -U option is also useful to consider. See mergemaster(8) for more information. [5] Usually this step is a no-op. However, from time to time you may need to do this if you get unknown user in the following step. It never hurts to do it all the time. You may need to install a new mergemaster (cd src/usr.sbin/mergemaster && make install) after the buildworld before this step if you last updated from current before 20130425 or from -stable before 20130430. [6] This only deletes old files and directories. Old libraries can be deleted by "make delete-old-libs", but you have to make sure that no program is using those libraries anymore. [8] In order to have a kernel that can run the 4.x binaries needed to do an installworld, you must include the COMPAT_FREEBSD4 option in your kernel. Failure to do so may leave you with a system that is hard to boot to recover. A similar kernel option COMPAT_FREEBSD5 is required to run the 5.x binaries on more recent kernels. And so on for COMPAT_FREEBSD6 and COMPAT_FREEBSD7. Make sure that you merge any new devices from GENERIC since the last time you updated your kernel config file. [9] If CPUTYPE is defined in your /etc/make.conf, make sure to use the "?=" instead of the "=" assignment operator, so that buildworld can override the CPUTYPE if it needs to. MAKEOBJDIRPREFIX must be defined in an environment variable, and not on the command line, or in /etc/make.conf. buildworld will warn if it is improperly defined. FORMAT: This file contains a list, in reverse chronological order, of major breakages in tracking -current. It is not guaranteed to be a complete list of such breakages, and only contains entries since September 23, 2011. If you need to see UPDATING entries from before that date, you will need to fetch an UPDATING file from an older FreeBSD release. Copyright information: Copyright 1998-2009 M. Warner Losh. All Rights Reserved. Redistribution, publication, translation and use, with or without modification, in full or in part, in any form or format of this document are permitted without further permission from the author. THIS DOCUMENT IS PROVIDED BY WARNER LOSH ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WARNER LOSH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Contact Warner Losh if you have any questions about your use of this document. $FreeBSD$ Index: head/contrib/mdocml/apropos.1 =================================================================== --- head/contrib/mdocml/apropos.1 (revision 337496) +++ head/contrib/mdocml/apropos.1 (revision 337497) @@ -1,486 +1,486 @@ .\" $Id: apropos.1,v 1.46 2017/07/04 23:40:01 schwarze Exp $ .\" .\" Copyright (c) 2011, 2012 Kristaps Dzonsons .\" Copyright (c) 2011, 2012, 2014, 2017 Ingo Schwarze .\" .\" 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. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. .\" -.Dd $Mdocdate: July 4 2017 $ +.Dd $Mdocdate: August 8 2018 $ .Dt APROPOS 1 .Os .Sh NAME .Nm apropos , .Nm whatis .Nd search manual page databases .Sh SYNOPSIS .Nm .Op Fl afk .Op Fl C Ar file .Op Fl M Ar path .Op Fl m Ar path .Op Fl O Ar outkey .Op Fl S Ar arch .Op Fl s Ar section .Ar expression ... .Sh DESCRIPTION The .Nm apropos and .Nm whatis utilities query manual page databases generated by .Xr makewhatis 8 , evaluating .Ar expression for each file in each database. By default, they display the names, section numbers, and description lines of all matching manuals. .Pp By default, .Nm searches for .Xr makewhatis 8 databases in the default paths stipulated by .Xr man 1 and uses case-insensitive substring matching .Pq the Cm = No operator over manual names and descriptions .Pq the Li \&Nm No and Li \&Nd No macro keys . Multiple terms imply pairwise .Fl o . .Pp .Nm whatis is a synonym for .Nm .Fl f . .Pp The options are as follows: .Bl -tag -width Ds .It Fl a Instead of showing only the title lines, show the complete manual pages, just like .Xr man 1 .Fl a would. If the standard output is a terminal device and .Fl c is not specified, use -.Xr more 1 +.Xr less 1 to paginate them. In .Fl a mode, the options .Fl IKOTW described in the .Xr mandoc 1 manual are also available. .It Fl C Ar file Specify an alternative configuration .Ar file in .Xr man.conf 5 format. .It Fl f Search for all words in .Ar expression in manual page names only. The search is case insensitive and matches whole words only. In this mode, macro keys, comparison operators, and logical operators are not available. .It Fl k Support the full .Ar expression syntax. It is the default for .Nm . .It Fl M Ar path Use the colon-separated path instead of the default list of paths searched for .Xr makewhatis 8 databases. Invalid paths, or paths without manual databases, are ignored. .It Fl m Ar path Prepend the colon-separated paths to the list of paths searched for .Xr makewhatis 8 databases. Invalid paths, or paths without manual databases, are ignored. .It Fl O Ar outkey Show the values associated with the key .Ar outkey instead of the manual descriptions. .It Fl S Ar arch Restrict the search to pages for the specified .Xr machine 1 architecture. .Ar arch is case insensitive. By default, pages for all architectures are shown. .It Fl s Ar section Restrict the search to the specified section of the manual. By default, pages from all sections are shown. See .Xr man 1 for a listing of sections. .El .Pp The options .Fl chlw are also supported and are documented in .Xr man 1 . The options .Fl fkl are mutually exclusive and override each other. .Pp An .Ar expression consists of search terms joined by logical operators .Fl a .Pq and and .Fl o .Pq or . The .Fl a operator has precedence over .Fl o and both are evaluated left-to-right. .Bl -tag -width Ds .It \&( Ar expr No \&) True if the subexpression .Ar expr is true. .It Ar expr1 Fl a Ar expr2 True if both .Ar expr1 and .Ar expr2 are true (logical .Sq and ) . .It Ar expr1 Oo Fl o Oc Ar expr2 True if .Ar expr1 and/or .Ar expr2 evaluate to true (logical .Sq or ) . .It Ar term True if .Ar term is satisfied. This has syntax .Sm off .Oo .Op Ar key Op , Ar key ... .Pq Cm = | \(ti .Oc .Ar val , .Sm on where .Ar key is an .Xr mdoc 7 macro to query and .Ar val is its value. See .Sx Macro Keys for a list of available keys. Operator .Cm = evaluates a substring, while .Cm \(ti evaluates a regular expression. .It Fl i Ar term If .Ar term is a regular expression, it is evaluated case-insensitively. Has no effect on substring terms. .El .Pp Results are sorted according to the following criteria: .Bl -enum .It The manpath directory tree the page is found in, according to the order specified with .Fl M , .Fl m , the .Ev MANPATH environment variable, the .Xr man.conf 5 configuration file, or the default documented in .Xr man.conf 5 . .It The section number in ascending numerical order. .It The page name in ascending .Xr ascii 7 alphabetical order, case-insensitive. .El .Pp Each output line is formatted as .Pp .D1 name[, name...](sec) \- description .Pp Where .Dq name is the manual's name, .Dq sec is the manual section, and .Dq description is the manual's short description. If an architecture is specified for the manual, it is displayed as .Pp .D1 name(sec/arch) \- description .Pp Resulting manuals may be accessed as .Pp .Dl $ man \-s sec name .Pp If an architecture is specified in the output, use .Pp .Dl $ man \-s sec \-S arch name .Ss Macro Keys Queries evaluate over a subset of .Xr mdoc 7 macros indexed by .Xr makewhatis 8 . In addition to the macro keys listed below, the special key .Cm any may be used to match any available macro key. .Pp Names and description: .Bl -column "xLix" description -offset indent -compact .It Li \&Nm Ta manual name .It Li \&Nd Ta one-line manual description .It Li arch Ta machine architecture (case-insensitive) .It Li sec Ta manual section number .El .Pp Sections and cross references: .Bl -column "xLix" description -offset indent -compact .It Li \&Sh Ta section header (excluding standard sections) .It Li \&Ss Ta subsection header .It Li \&Xr Ta cross reference to another manual page .It Li \&Rs Ta bibliographic reference .El .Pp Semantic markup for command line utilities: .Bl -column "xLix" description -offset indent -compact .It Li \&Fl Ta command line options (flags) .It Li \&Cm Ta command modifier .It Li \&Ar Ta command argument .It Li \&Ic Ta internal or interactive command .It Li \&Ev Ta environmental variable .It Li \&Pa Ta file system path .El .Pp Semantic markup for function libraries: .Bl -column "xLix" description -offset indent -compact .It Li \&Lb Ta function library name .It Li \&In Ta include file .It Li \&Ft Ta function return type .It Li \&Fn Ta function name .It Li \&Fa Ta function argument type and name .It Li \&Vt Ta variable type .It Li \&Va Ta variable name .It Li \&Dv Ta defined variable or preprocessor constant .It Li \&Er Ta error constant .It Li \&Ev Ta environmental variable .El .Pp Various semantic markup: .Bl -column "xLix" description -offset indent -compact .It Li \&An Ta author name .It Li \&Lk Ta hyperlink .It Li \&Mt Ta Do mailto Dc hyperlink .It Li \&Cd Ta kernel configuration declaration .It Li \&Ms Ta mathematical symbol .It Li \&Tn Ta tradename .El .Pp Physical markup: .Bl -column "xLix" description -offset indent -compact .It Li \&Em Ta italic font or underline .It Li \&Sy Ta boldface font .It Li \&Li Ta typewriter font .El .Pp Text production: .Bl -column "xLix" description -offset indent -compact .It Li \&St Ta reference to a standards document .It Li \&At Ta At No version reference .It Li \&Bx Ta Bx No version reference .It Li \&Bsx Ta Bsx No version reference .It Li \&Nx Ta Nx No version reference .It Li \&Fx Ta Fx No version reference .It Li \&Ox Ta Ox No version reference .It Li \&Dx Ta Dx No version reference .El .Sh ENVIRONMENT .Bl -tag -width MANPAGER .It Ev MANPAGER Any non-empty value of the environment variable .Ev MANPAGER is used instead of the standard pagination program, -.Xr more 1 ; +.Xr less 1 ; see .Xr man 1 for details. Only used if .Fl a or .Fl l is specified. .It Ev MANPATH A colon-separated list of directories to search for manual pages; see .Xr man 1 for details. Overridden by .Fl M , ignored if .Fl l is specified. .It Ev PAGER Specifies the pagination program to use when .Ev MANPAGER is not defined. If neither PAGER nor MANPAGER is defined, -.Xr more 1 +.Xr less 1 .Fl s is used. Only used if .Fl a or .Fl l is specified. .El .Sh FILES .Bl -tag -width "/etc/man.conf" -compact .It Pa mandoc.db name of the .Xr makewhatis 8 keyword database .It Pa /etc/man.conf default .Xr man 1 configuration file .El .Sh EXIT STATUS .Ex -std .Sh EXAMPLES Search for .Qq .cf as a substring of manual names and descriptions: .Pp .Dl $ apropos .cf .Pp Include matches for .Qq .cnf and .Qq .conf as well: .Pp .Dl $ apropos .cf .cnf .conf .Pp Search in names and descriptions using a regular expression: .Pp .Dl $ apropos \(aq\(tiset.?[ug]id\(aq .Pp Search for manuals in the library section mentioning both the .Qq optind and the .Qq optarg variables: .Pp .Dl $ apropos \-s 3 Va=optind \-a Va=optarg .Pp Do exactly the same as calling .Nm whatis with the argument .Qq ssh : .Pp .Dl $ apropos \-\- \-i \(aqNm\(ti[[:<:]]ssh[[:>:]]\(aq .Pp The following two invocations are equivalent: .Pp .D1 Li $ apropos -S Ar arch Li -s Ar section expression .Bd -ragged -offset indent .Li $ apropos \e( Ar expression Li \e) .Li -a arch\(ti^( Ns Ar arch Ns Li |any)$ .Li -a sec\(ti^ Ns Ar section Ns Li $ .Ed .Sh SEE ALSO .Xr man 1 , .Xr re_format 7 , .Xr makewhatis 8 .Sh HISTORY Part of the functionality of .Nm whatis was already provided by the former .Nm manwhere utility in .Bx 1 . The .Nm and .Nm whatis utilities first appeared in .Bx 2 . They were rewritten from scratch for .Ox 5.6 . .Pp The .Fl M option and the .Ev MANPATH variable first appeared in .Bx 4.3 ; .Fl m in .Bx 4.3 Reno ; .Fl C in .Bx 4.4 Lite1 ; and .Fl S and .Fl s in .Ox 4.5 for .Nm and in .Ox 5.6 for .Nm whatis . The options .Fl acfhIKklOTWw appeared in .Ox 5.7 . .Sh AUTHORS .An -nosplit .An Bill Joy wrote .Nm manwhere in 1977 and the original .Bx .Nm and .Nm whatis in February 1979. The current version was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv and .An Ingo Schwarze Aq Mt schwarze@openbsd.org . Index: head/contrib/mdocml/main.c =================================================================== --- head/contrib/mdocml/main.c (revision 337496) +++ head/contrib/mdocml/main.c (revision 337497) @@ -1,1185 +1,1185 @@ /* $Id: main.c,v 1.301 2017/07/26 10:21:55 schwarze Exp $ */ /* * Copyright (c) 2008-2012 Kristaps Dzonsons * Copyright (c) 2010-2012, 2014-2017 Ingo Schwarze * Copyright (c) 2010 Joerg Sonnenberger * * 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. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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. */ #include "config.h" #include #include /* MACHINE */ #include #include #include #if HAVE_ERR #include #endif #include #include #include #if HAVE_SANDBOX_INIT #include #endif #include #include #include #include #include #include #include #include "mandoc_aux.h" #include "mandoc.h" #include "mandoc_xr.h" #include "roff.h" #include "mdoc.h" #include "man.h" #include "tag.h" #include "main.h" #include "manconf.h" #include "mansearch.h" enum outmode { OUTMODE_DEF = 0, OUTMODE_FLN, OUTMODE_LST, OUTMODE_ALL, OUTMODE_ONE }; enum outt { OUTT_ASCII = 0, /* -Tascii */ OUTT_LOCALE, /* -Tlocale */ OUTT_UTF8, /* -Tutf8 */ OUTT_TREE, /* -Ttree */ OUTT_MAN, /* -Tman */ OUTT_HTML, /* -Thtml */ OUTT_MARKDOWN, /* -Tmarkdown */ OUTT_LINT, /* -Tlint */ OUTT_PS, /* -Tps */ OUTT_PDF /* -Tpdf */ }; struct curparse { struct mparse *mp; struct manoutput *outopts; /* output options */ void *outdata; /* data for output */ char *os_s; /* operating system for display */ int wstop; /* stop after a file with a warning */ enum mandocerr mmin; /* ignore messages below this */ enum mandoc_os os_e; /* check base system conventions */ enum outt outtype; /* which output to use */ }; int mandocdb(int, char *[]); static void check_xr(const char *); static int fs_lookup(const struct manpaths *, size_t ipath, const char *, const char *, const char *, struct manpage **, size_t *); static int fs_search(const struct mansearch *, const struct manpaths *, int, char**, struct manpage **, size_t *); static int koptions(int *, char *); static void moptions(int *, char *); static void mmsg(enum mandocerr, enum mandoclevel, const char *, int, int, const char *); static void outdata_alloc(struct curparse *); static void parse(struct curparse *, int, const char *); static void passthrough(const char *, int, int); static pid_t spawn_pager(struct tag_files *); static int toptions(struct curparse *, char *); static void usage(enum argmode) __attribute__((__noreturn__)); static int woptions(struct curparse *, char *); static const int sec_prios[] = {1, 4, 5, 8, 6, 3, 7, 2, 9}; static char help_arg[] = "help"; static char *help_argv[] = {help_arg, NULL}; static enum mandoclevel rc; static FILE *mmsg_stream; int main(int argc, char *argv[]) { struct manconf conf; struct mansearch search; struct curparse curp; struct tag_files *tag_files; struct manpage *res, *resp; const char *progname, *sec, *thisarg; char *conf_file, *defpaths, *auxpaths; char *oarg; unsigned char *uc; size_t i, sz; int prio, best_prio; enum outmode outmode; int fd; int show_usage; int options; int use_pager; int status, signum; int c; pid_t pager_pid, tc_pgid, man_pgid, pid; #if HAVE_PROGNAME progname = getprogname(); #else if (argc < 1) progname = mandoc_strdup("mandoc"); else if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else ++progname; setprogname(progname); #endif if (strncmp(progname, "mandocdb", 8) == 0 || strcmp(progname, BINM_MAKEWHATIS) == 0) return mandocdb(argc, argv); #if HAVE_PLEDGE if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif #if HAVE_SANDBOX_INIT if (sandbox_init(kSBXProfileNoInternet, SANDBOX_NAMED, NULL) == -1) errx((int)MANDOCLEVEL_SYSERR, "sandbox_init"); #endif /* Search options. */ memset(&conf, 0, sizeof(conf)); conf_file = defpaths = NULL; auxpaths = NULL; memset(&search, 0, sizeof(struct mansearch)); search.outkey = "Nd"; oarg = NULL; if (strcmp(progname, BINM_MAN) == 0) search.argmode = ARG_NAME; else if (strcmp(progname, BINM_APROPOS) == 0) search.argmode = ARG_EXPR; else if (strcmp(progname, BINM_WHATIS) == 0) search.argmode = ARG_WORD; else if (strncmp(progname, "help", 4) == 0) search.argmode = ARG_NAME; else search.argmode = ARG_FILE; /* Parser and formatter options. */ memset(&curp, 0, sizeof(struct curparse)); curp.outtype = OUTT_LOCALE; curp.mmin = MANDOCERR_MAX; curp.outopts = &conf.output; options = MPARSE_SO | MPARSE_UTF8 | MPARSE_LATIN1; mmsg_stream = stderr; use_pager = 1; tag_files = NULL; show_usage = 0; outmode = OUTMODE_DEF; while ((c = getopt(argc, argv, "aC:cfhI:iK:klM:m:O:S:s:T:VW:w")) != -1) { if (c == 'i' && search.argmode == ARG_EXPR) { optind--; break; } switch (c) { case 'a': outmode = OUTMODE_ALL; break; case 'C': conf_file = optarg; break; case 'c': use_pager = 0; break; case 'f': search.argmode = ARG_WORD; break; case 'h': conf.output.synopsisonly = 1; use_pager = 0; outmode = OUTMODE_ALL; break; case 'I': if (strncmp(optarg, "os=", 3)) { warnx("-I %s: Bad argument", optarg); return (int)MANDOCLEVEL_BADARG; } if (curp.os_s != NULL) { warnx("-I %s: Duplicate argument", optarg); return (int)MANDOCLEVEL_BADARG; } curp.os_s = mandoc_strdup(optarg + 3); break; case 'K': if ( ! koptions(&options, optarg)) return (int)MANDOCLEVEL_BADARG; break; case 'k': search.argmode = ARG_EXPR; break; case 'l': search.argmode = ARG_FILE; outmode = OUTMODE_ALL; break; case 'M': defpaths = optarg; break; case 'm': auxpaths = optarg; break; case 'O': oarg = optarg; break; case 'S': search.arch = optarg; break; case 's': search.sec = optarg; break; case 'T': if ( ! toptions(&curp, optarg)) return (int)MANDOCLEVEL_BADARG; break; case 'W': if ( ! woptions(&curp, optarg)) return (int)MANDOCLEVEL_BADARG; break; case 'w': outmode = OUTMODE_FLN; break; default: show_usage = 1; break; } } if (show_usage) usage(search.argmode); /* Postprocess options. */ if (outmode == OUTMODE_DEF) { switch (search.argmode) { case ARG_FILE: outmode = OUTMODE_ALL; use_pager = 0; break; case ARG_NAME: outmode = OUTMODE_ONE; break; default: outmode = OUTMODE_LST; break; } } if (oarg != NULL) { if (outmode == OUTMODE_LST) search.outkey = oarg; else { while (oarg != NULL) { thisarg = oarg; if (manconf_output(&conf.output, strsep(&oarg, ","), 0) == 0) continue; warnx("-O %s: Bad argument", thisarg); return (int)MANDOCLEVEL_BADARG; } } } if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST || !isatty(STDOUT_FILENO)) use_pager = 0; #if HAVE_PLEDGE if (!use_pager) if (pledge("stdio rpath", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif /* Parse arguments. */ if (argc > 0) { argc -= optind; argv += optind; } resp = NULL; /* * Quirks for help(1) * and for a man(1) section argument without -s. */ if (search.argmode == ARG_NAME) { if (*progname == 'h') { if (argc == 0) { argv = help_argv; argc = 1; } } else if (argc > 1 && ((uc = (unsigned char *)argv[0]) != NULL) && ((isdigit(uc[0]) && (uc[1] == '\0' || (isalpha(uc[1]) && uc[2] == '\0'))) || (uc[0] == 'n' && uc[1] == '\0'))) { search.sec = (char *)uc; argv++; argc--; } if (search.arch == NULL) search.arch = getenv("MACHINE"); #ifdef MACHINE if (search.arch == NULL) search.arch = MACHINE; #endif } rc = MANDOCLEVEL_OK; /* man(1), whatis(1), apropos(1) */ if (search.argmode != ARG_FILE) { if (search.argmode == ARG_NAME && outmode == OUTMODE_ONE) search.firstmatch = 1; /* Access the mandoc database. */ manconf_parse(&conf, conf_file, defpaths, auxpaths); if ( ! mansearch(&search, &conf.manpath, argc, argv, &res, &sz)) usage(search.argmode); if (sz == 0) { if (search.argmode == ARG_NAME) fs_search(&search, &conf.manpath, argc, argv, &res, &sz); else warnx("nothing appropriate"); } if (sz == 0) { rc = MANDOCLEVEL_BADARG; goto out; } /* * For standard man(1) and -a output mode, * prepare for copying filename pointers * into the program parameter array. */ if (outmode == OUTMODE_ONE) { argc = 1; best_prio = 20; } else if (outmode == OUTMODE_ALL) argc = (int)sz; /* Iterate all matching manuals. */ resp = res; for (i = 0; i < sz; i++) { if (outmode == OUTMODE_FLN) puts(res[i].file); else if (outmode == OUTMODE_LST) printf("%s - %s\n", res[i].names, res[i].output == NULL ? "" : res[i].output); else if (outmode == OUTMODE_ONE) { /* Search for the best section. */ sec = res[i].file; sec += strcspn(sec, "123456789"); if (sec[0] == '\0') continue; prio = sec_prios[sec[0] - '1']; if (sec[1] != '/') prio += 10; if (prio >= best_prio) continue; best_prio = prio; resp = res + i; } } /* * For man(1), -a and -i output mode, fall through * to the main mandoc(1) code iterating files * and running the parsers on each of them. */ if (outmode == OUTMODE_FLN || outmode == OUTMODE_LST) goto out; } /* mandoc(1) */ #if HAVE_PLEDGE if (use_pager) { if (pledge("stdio rpath tmppath tty proc exec", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); } else { if (pledge("stdio rpath", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); } #endif if (search.argmode == ARG_FILE) moptions(&options, auxpaths); mchars_alloc(); curp.mp = mparse_alloc(options, curp.mmin, mmsg, curp.os_e, curp.os_s); /* * Conditionally start up the lookaside buffer before parsing. */ if (OUTT_MAN == curp.outtype) mparse_keep(curp.mp); if (argc < 1) { if (use_pager) tag_files = tag_init(); parse(&curp, STDIN_FILENO, ""); } while (argc > 0) { fd = mparse_open(curp.mp, resp != NULL ? resp->file : *argv); if (fd != -1) { if (use_pager) { tag_files = tag_init(); use_pager = 0; } if (resp == NULL) parse(&curp, fd, *argv); else if (resp->form == FORM_SRC) { /* For .so only; ignore failure. */ (void)chdir(conf.manpath.paths[resp->ipath]); parse(&curp, fd, resp->file); } else passthrough(resp->file, fd, conf.output.synopsisonly); if (argc > 1 && curp.outtype <= OUTT_UTF8) { if (curp.outdata == NULL) outdata_alloc(&curp); terminal_sepline(curp.outdata); } } else if (rc < MANDOCLEVEL_ERROR) rc = MANDOCLEVEL_ERROR; if (MANDOCLEVEL_OK != rc && curp.wstop) break; if (resp != NULL) resp++; else argv++; if (--argc) mparse_reset(curp.mp); } if (curp.outdata != NULL) { switch (curp.outtype) { case OUTT_HTML: html_free(curp.outdata); break; case OUTT_UTF8: case OUTT_LOCALE: case OUTT_ASCII: ascii_free(curp.outdata); break; case OUTT_PDF: case OUTT_PS: pspdf_free(curp.outdata); break; default: break; } } mandoc_xr_free(); mparse_free(curp.mp); mchars_free(); out: if (search.argmode != ARG_FILE) { manconf_free(&conf); mansearch_free(res, sz); } free(curp.os_s); /* * When using a pager, finish writing both temporary files, * fork it, wait for the user to close it, and clean up. */ if (tag_files != NULL) { fclose(stdout); tag_write(); man_pgid = getpgid(0); tag_files->tcpgid = man_pgid == getpid() ? getpgid(getppid()) : man_pgid; pager_pid = 0; signum = SIGSTOP; for (;;) { /* Stop here until moved to the foreground. */ tc_pgid = tcgetpgrp(tag_files->ofd); if (tc_pgid != man_pgid) { if (tc_pgid == pager_pid) { (void)tcsetpgrp(tag_files->ofd, man_pgid); if (signum == SIGTTIN) continue; } else tag_files->tcpgid = tc_pgid; kill(0, signum); continue; } /* Once in the foreground, activate the pager. */ if (pager_pid) { (void)tcsetpgrp(tag_files->ofd, pager_pid); kill(pager_pid, SIGCONT); } else pager_pid = spawn_pager(tag_files); /* Wait for the pager to stop or exit. */ while ((pid = waitpid(pager_pid, &status, WUNTRACED)) == -1 && errno == EINTR) continue; if (pid == -1) { warn("wait"); rc = MANDOCLEVEL_SYSERR; break; } if (!WIFSTOPPED(status)) break; signum = WSTOPSIG(status); } tag_unlink(); } return (int)rc; } static void usage(enum argmode argmode) { switch (argmode) { case ARG_FILE: fputs("usage: mandoc [-ac] [-I os=name] " "[-K encoding] [-mdoc | -man] [-O options]\n" "\t [-T output] [-W level] [file ...]\n", stderr); break; case ARG_NAME: fputs("usage: man [-acfhklw] [-C file] [-M path] " "[-m path] [-S subsection]\n" "\t [[-s] section] name ...\n", stderr); break; case ARG_WORD: fputs("usage: whatis [-afk] [-C file] " "[-M path] [-m path] [-O outkey] [-S arch]\n" "\t [-s section] name ...\n", stderr); break; case ARG_EXPR: fputs("usage: apropos [-afk] [-C file] " "[-M path] [-m path] [-O outkey] [-S arch]\n" "\t [-s section] expression ...\n", stderr); break; } exit((int)MANDOCLEVEL_BADARG); } static int fs_lookup(const struct manpaths *paths, size_t ipath, const char *sec, const char *arch, const char *name, struct manpage **res, size_t *ressz) { glob_t globinfo; struct manpage *page; char *file; int globres; enum form form; form = FORM_SRC; mandoc_asprintf(&file, "%s/man%s/%s.%s", paths->paths[ipath], sec, name, sec); if (access(file, R_OK) != -1) goto found; free(file); mandoc_asprintf(&file, "%s/cat%s/%s.0", paths->paths[ipath], sec, name); if (access(file, R_OK) != -1) { form = FORM_CAT; goto found; } free(file); if (arch != NULL) { mandoc_asprintf(&file, "%s/man%s/%s/%s.%s", paths->paths[ipath], sec, arch, name, sec); if (access(file, R_OK) != -1) goto found; free(file); } mandoc_asprintf(&file, "%s/man%s/%s.[01-9]*", paths->paths[ipath], sec, name); globres = glob(file, 0, NULL, &globinfo); if (globres != 0 && globres != GLOB_NOMATCH) warn("%s: glob", file); free(file); if (globres == 0) file = mandoc_strdup(*globinfo.gl_pathv); globfree(&globinfo); if (globres == 0) goto found; if (res != NULL || ipath + 1 != paths->sz) return 0; mandoc_asprintf(&file, "%s.%s", name, sec); globres = access(file, R_OK); free(file); return globres != -1; found: warnx("outdated mandoc.db lacks %s(%s) entry, run %s %s", name, sec, BINM_MAKEWHATIS, paths->paths[ipath]); if (res == NULL) { free(file); return 1; } *res = mandoc_reallocarray(*res, ++*ressz, sizeof(struct manpage)); page = *res + (*ressz - 1); page->file = file; page->names = NULL; page->output = NULL; page->ipath = ipath; page->bits = NAME_FILE & NAME_MASK; page->sec = (*sec >= '1' && *sec <= '9') ? *sec - '1' + 1 : 10; page->form = form; return 1; } static int fs_search(const struct mansearch *cfg, const struct manpaths *paths, int argc, char **argv, struct manpage **res, size_t *ressz) { const char *const sections[] = {"1", "8", "6", "2", "3", "5", "7", "4", "9", "3p"}; const size_t nsec = sizeof(sections)/sizeof(sections[0]); size_t ipath, isec, lastsz; assert(cfg->argmode == ARG_NAME); if (res != NULL) *res = NULL; *ressz = lastsz = 0; while (argc) { for (ipath = 0; ipath < paths->sz; ipath++) { if (cfg->sec != NULL) { if (fs_lookup(paths, ipath, cfg->sec, cfg->arch, *argv, res, ressz) && cfg->firstmatch) return 1; } else for (isec = 0; isec < nsec; isec++) if (fs_lookup(paths, ipath, sections[isec], cfg->arch, *argv, res, ressz) && cfg->firstmatch) return 1; } if (res != NULL && *ressz == lastsz) warnx("No entry for %s in the manual.", *argv); lastsz = *ressz; argv++; argc--; } return 0; } static void parse(struct curparse *curp, int fd, const char *file) { enum mandoclevel rctmp; struct roff_man *man; /* Begin by parsing the file itself. */ assert(file); assert(fd >= 0); rctmp = mparse_readfd(curp->mp, fd, file); if (fd != STDIN_FILENO) close(fd); if (rc < rctmp) rc = rctmp; /* * With -Wstop and warnings or errors of at least the requested * level, do not produce output. */ if (rctmp != MANDOCLEVEL_OK && curp->wstop) return; if (curp->outdata == NULL) outdata_alloc(curp); mparse_result(curp->mp, &man, NULL); /* Execute the out device, if it exists. */ if (man == NULL) return; mandoc_xr_reset(); if (man->macroset == MACROSET_MDOC) { if (curp->outtype != OUTT_TREE || !curp->outopts->noval) mdoc_validate(man); switch (curp->outtype) { case OUTT_HTML: html_mdoc(curp->outdata, man); break; case OUTT_TREE: tree_mdoc(curp->outdata, man); break; case OUTT_MAN: man_mdoc(curp->outdata, man); break; case OUTT_PDF: case OUTT_ASCII: case OUTT_UTF8: case OUTT_LOCALE: case OUTT_PS: terminal_mdoc(curp->outdata, man); break; case OUTT_MARKDOWN: markdown_mdoc(curp->outdata, man); break; default: break; } } if (man->macroset == MACROSET_MAN) { if (curp->outtype != OUTT_TREE || !curp->outopts->noval) man_validate(man); switch (curp->outtype) { case OUTT_HTML: html_man(curp->outdata, man); break; case OUTT_TREE: tree_man(curp->outdata, man); break; case OUTT_MAN: man_man(curp->outdata, man); break; case OUTT_PDF: case OUTT_ASCII: case OUTT_UTF8: case OUTT_LOCALE: case OUTT_PS: terminal_man(curp->outdata, man); break; default: break; } } if (curp->mmin < MANDOCERR_STYLE) check_xr(file); mparse_updaterc(curp->mp, &rc); } static void check_xr(const char *file) { static struct manpaths paths; struct mansearch search; struct mandoc_xr *xr; char *cp; size_t sz; if (paths.sz == 0) manpath_base(&paths); for (xr = mandoc_xr_get(); xr != NULL; xr = xr->next) { if (xr->line == -1) continue; search.arch = NULL; search.sec = xr->sec; search.outkey = NULL; search.argmode = ARG_NAME; search.firstmatch = 1; if (mansearch(&search, &paths, 1, &xr->name, NULL, &sz)) continue; if (fs_search(&search, &paths, 1, &xr->name, NULL, &sz)) continue; if (xr->count == 1) mandoc_asprintf(&cp, "Xr %s %s", xr->name, xr->sec); else mandoc_asprintf(&cp, "Xr %s %s (%d times)", xr->name, xr->sec, xr->count); mmsg(MANDOCERR_XR_BAD, MANDOCLEVEL_STYLE, file, xr->line, xr->pos + 1, cp); free(cp); } } static void outdata_alloc(struct curparse *curp) { switch (curp->outtype) { case OUTT_HTML: curp->outdata = html_alloc(curp->outopts); break; case OUTT_UTF8: curp->outdata = utf8_alloc(curp->outopts); break; case OUTT_LOCALE: curp->outdata = locale_alloc(curp->outopts); break; case OUTT_ASCII: curp->outdata = ascii_alloc(curp->outopts); break; case OUTT_PDF: curp->outdata = pdf_alloc(curp->outopts); break; case OUTT_PS: curp->outdata = ps_alloc(curp->outopts); break; default: break; } } static void passthrough(const char *file, int fd, int synopsis_only) { const char synb[] = "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"; const char synr[] = "SYNOPSIS"; FILE *stream; const char *syscall; char *line, *cp; size_t linesz; ssize_t len, written; int print; line = NULL; linesz = 0; if (fflush(stdout) == EOF) { syscall = "fflush"; goto fail; } if ((stream = fdopen(fd, "r")) == NULL) { close(fd); syscall = "fdopen"; goto fail; } print = 0; while ((len = getline(&line, &linesz, stream)) != -1) { cp = line; if (synopsis_only) { if (print) { if ( ! isspace((unsigned char)*cp)) goto done; while (isspace((unsigned char)*cp)) { cp++; len--; } } else { if (strcmp(cp, synb) == 0 || strcmp(cp, synr) == 0) print = 1; continue; } } for (; len > 0; len -= written) { if ((written = write(STDOUT_FILENO, cp, len)) != -1) continue; fclose(stream); syscall = "write"; goto fail; } } if (ferror(stream)) { fclose(stream); syscall = "getline"; goto fail; } done: free(line); fclose(stream); return; fail: free(line); warn("%s: SYSERR: %s", file, syscall); if (rc < MANDOCLEVEL_SYSERR) rc = MANDOCLEVEL_SYSERR; } static int koptions(int *options, char *arg) { if ( ! strcmp(arg, "utf-8")) { *options |= MPARSE_UTF8; *options &= ~MPARSE_LATIN1; } else if ( ! strcmp(arg, "iso-8859-1")) { *options |= MPARSE_LATIN1; *options &= ~MPARSE_UTF8; } else if ( ! strcmp(arg, "us-ascii")) { *options &= ~(MPARSE_UTF8 | MPARSE_LATIN1); } else { warnx("-K %s: Bad argument", arg); return 0; } return 1; } static void moptions(int *options, char *arg) { if (arg == NULL) return; if (strcmp(arg, "doc") == 0) *options |= MPARSE_MDOC; else if (strcmp(arg, "an") == 0) *options |= MPARSE_MAN; } static int toptions(struct curparse *curp, char *arg) { if (0 == strcmp(arg, "ascii")) curp->outtype = OUTT_ASCII; else if (0 == strcmp(arg, "lint")) { curp->outtype = OUTT_LINT; curp->mmin = MANDOCERR_BASE; mmsg_stream = stdout; } else if (0 == strcmp(arg, "tree")) curp->outtype = OUTT_TREE; else if (0 == strcmp(arg, "man")) curp->outtype = OUTT_MAN; else if (0 == strcmp(arg, "html")) curp->outtype = OUTT_HTML; else if (0 == strcmp(arg, "markdown")) curp->outtype = OUTT_MARKDOWN; else if (0 == strcmp(arg, "utf8")) curp->outtype = OUTT_UTF8; else if (0 == strcmp(arg, "locale")) curp->outtype = OUTT_LOCALE; else if (0 == strcmp(arg, "ps")) curp->outtype = OUTT_PS; else if (0 == strcmp(arg, "pdf")) curp->outtype = OUTT_PDF; else { warnx("-T %s: Bad argument", arg); return 0; } return 1; } static int woptions(struct curparse *curp, char *arg) { char *v, *o; const char *toks[11]; toks[0] = "stop"; toks[1] = "all"; toks[2] = "base"; toks[3] = "style"; toks[4] = "warning"; toks[5] = "error"; toks[6] = "unsupp"; toks[7] = "fatal"; toks[8] = "openbsd"; toks[9] = "netbsd"; toks[10] = NULL; while (*arg) { o = arg; switch (getsubopt(&arg, (char * const *)toks, &v)) { case 0: curp->wstop = 1; break; case 1: case 2: curp->mmin = MANDOCERR_BASE; break; case 3: curp->mmin = MANDOCERR_STYLE; break; case 4: curp->mmin = MANDOCERR_WARNING; break; case 5: curp->mmin = MANDOCERR_ERROR; break; case 6: curp->mmin = MANDOCERR_UNSUPP; break; case 7: curp->mmin = MANDOCERR_MAX; break; case 8: curp->mmin = MANDOCERR_BASE; curp->os_e = MANDOC_OS_OPENBSD; break; case 9: curp->mmin = MANDOCERR_BASE; curp->os_e = MANDOC_OS_NETBSD; break; default: warnx("-W %s: Bad argument", o); return 0; } } return 1; } static void mmsg(enum mandocerr t, enum mandoclevel lvl, const char *file, int line, int col, const char *msg) { const char *mparse_msg; fprintf(mmsg_stream, "%s: %s:", getprogname(), file == NULL ? "" : file); if (line) fprintf(mmsg_stream, "%d:%d:", line, col + 1); fprintf(mmsg_stream, " %s", mparse_strlevel(lvl)); if ((mparse_msg = mparse_strerror(t)) != NULL) fprintf(mmsg_stream, ": %s", mparse_msg); if (msg) fprintf(mmsg_stream, ": %s", msg); fputc('\n', mmsg_stream); } static pid_t spawn_pager(struct tag_files *tag_files) { const struct timespec timeout = { 0, 100000000 }; /* 0.1s */ #define MAX_PAGER_ARGS 16 char *argv[MAX_PAGER_ARGS]; const char *pager; char *cp; size_t cmdlen; int argc; pid_t pager_pid; pager = getenv("MANPAGER"); if (pager == NULL || *pager == '\0') pager = getenv("PAGER"); if (pager == NULL || *pager == '\0') - pager = "more -s"; + pager = "less -s"; cp = mandoc_strdup(pager); /* * Parse the pager command into words. * Intentionally do not do anything fancy here. */ argc = 0; while (argc + 4 < MAX_PAGER_ARGS) { argv[argc++] = cp; cp = strchr(cp, ' '); if (cp == NULL) break; *cp++ = '\0'; while (*cp == ' ') cp++; if (*cp == '\0') break; } /* For less(1), use the tag file. */ if ((cmdlen = strlen(argv[0])) >= 4) { cp = argv[0] + cmdlen - 4; if (strcmp(cp, "less") == 0) { argv[argc++] = mandoc_strdup("-T"); argv[argc++] = tag_files->tfn; } } argv[argc++] = tag_files->ofn; argv[argc] = NULL; switch (pager_pid = fork()) { case -1: err((int)MANDOCLEVEL_SYSERR, "fork"); case 0: break; default: (void)setpgid(pager_pid, 0); (void)tcsetpgrp(tag_files->ofd, pager_pid); #if HAVE_PLEDGE if (pledge("stdio rpath tmppath tty proc", NULL) == -1) err((int)MANDOCLEVEL_SYSERR, "pledge"); #endif tag_files->pager_pid = pager_pid; return pager_pid; } /* The child process becomes the pager. */ if (dup2(tag_files->ofd, STDOUT_FILENO) == -1) err((int)MANDOCLEVEL_SYSERR, "pager stdout"); close(tag_files->ofd); close(tag_files->tfd); /* Do not start the pager before controlling the terminal. */ while (tcgetpgrp(STDOUT_FILENO) != getpid()) nanosleep(&timeout, NULL); execvp(argv[0], argv); err((int)MANDOCLEVEL_SYSERR, "exec %s", argv[0]); } Index: head/contrib/mdocml/man.1 =================================================================== --- head/contrib/mdocml/man.1 (revision 337496) +++ head/contrib/mdocml/man.1 (revision 337497) @@ -1,384 +1,384 @@ .\" $Id: man.1,v 1.29 2017/05/17 23:23:00 schwarze Exp $ .\" .\" Copyright (c) 1989, 1990, 1993 .\" The Regents of the University of California. All rights reserved. .\" Copyright (c) 2003, 2007, 2008, 2014 Jason McIntyre .\" Copyright (c) 2010, 2011, 2014-2017 Ingo Schwarze .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)man.1 8.2 (Berkeley) 1/2/94 .\" -.Dd $Mdocdate: May 17 2017 $ +.Dd $Mdocdate: August 8 2018 $ .Dt MAN 1 .Os .Sh NAME .Nm man .Nd display manual pages .Sh SYNOPSIS .Nm man .Op Fl acfhklw .Op Fl C Ar file .Op Fl M Ar path .Op Fl m Ar path .Op Fl S Ar subsection .Op Oo Fl s Oc Ar section .Ar name ... .Sh DESCRIPTION The .Nm utility displays the manual pages entitled .Ar name . Pages may be selected according to a specific category .Pq Ar section or machine architecture .Pq Ar subsection . .Pp The options are as follows: .Bl -tag -width Ds .It Fl a Display all matching manual pages. Normally, only the first page found is displayed. .It Fl C Ar file Use the specified .Ar file instead of the default configuration file. This permits users to configure their own manual environment. See .Xr man.conf 5 for a description of the contents of this file. .It Fl c Copy the manual page to the standard output instead of using -.Xr more 1 +.Xr less 1 to paginate it. This is done by default if the standard output is not a terminal device. .It Fl f A synonym for .Xr whatis 1 . It searches for .Ar name in manual page names and displays the header lines from all matching pages. The search is case insensitive and matches whole words only. .It Fl h Display only the SYNOPSIS lines of the requested manual pages. Implies .Fl a and .Fl c . .It Fl k A synonym for .Xr apropos 1 . Instead of .Ar name , an expression can be provided using the syntax described in the .Xr apropos 1 manual. By default, it displays the header lines of all matching pages. .It Fl l A synonym for .Xr mandoc 1 .Fl a . The .Ar name arguments are interpreted as filenames. No search is done and .Ar file , .Ar path , .Ar section , .Ar subsection , and .Fl w are ignored. .It Fl M Ar path Override the list of standard directories which .Nm searches for manual pages. The supplied .Ar path must be a colon .Pq Ql \&: separated list of directories. This search path may also be set using the environment variable .Ev MANPATH . .It Fl m Ar path Augment the list of standard directories which .Nm searches for manual pages. The supplied .Ar path must be a colon .Pq Ql \&: separated list of directories. These directories will be searched before the standard directories or the directories specified using the .Fl M option or the .Ev MANPATH environment variable. .It Fl S Ar subsection Only show pages for the specified .Xr machine 1 architecture. .Ar subsection is case insensitive. .Pp By default manual pages for all architectures are installed. Therefore this option can be used to view pages for one architecture whilst using another. .Pp This option overrides the .Ev MACHINE environment variable. .It Oo Fl s Oc Ar section Only select manuals from the specified .Ar section . The currently available sections are: .Pp .Bl -tag -width "localXXX" -offset indent -compact .It 1 General commands .Pq tools and utilities . .It 2 System calls and error numbers. .It 3 Library functions. .It 3p .Xr perl 1 programmer's reference guide. .It 4 Device drivers. .It 5 File formats. .It 6 Games. .It 7 Miscellaneous information. .It 8 System maintenance and operation commands. .It 9 Kernel internals. .El .Pp If not specified and a match is found in more than one section, the first match is selected from the following list: 1, 8, 6, 2, 3, 5, 7, 4, 9, 3p. .It Fl w List the pathnames of all matching manual pages instead of displaying any of them. .El .Pp The options .Fl IKOTW are also supported and are documented in .Xr mandoc 1 . The options .Fl fkl are mutually exclusive and override each other. .Pp Guidelines for writing man pages can be found in .Xr mdoc 7 . .Pp If both a formatted and an unformatted version of the same manual page, for example .Pa cat1/foo.0 and .Pa man1/foo.1 , exist in the same directory, only the unformatted version is used. .Sh ENVIRONMENT .Bl -tag -width MANPATHX .It Ev MACHINE As some manual pages are intended only for specific architectures, .Nm searches any subdirectories, with the same name as the current architecture, in every directory which it searches. Machine specific areas are checked before general areas. The current machine type may be overridden by setting the environment variable .Ev MACHINE to the name of a specific architecture, or with the .Fl S option. .Ev MACHINE is case insensitive. .It Ev MANPAGER Any non-empty value of the environment variable .Ev MANPAGER is used instead of the standard pagination program, -.Xr more 1 . +.Xr less 1 . If .Xr less 1 is used, the interactive .Ic :t command can be used to go to the definitions of various terms, for example command line options, command modifiers, internal commands, environment variables, function names, preprocessor macros, .Xr errno 2 values, and some other emphasized words. Some terms may have defining text at more than one place. In that case, the .Xr less 1 interactive commands .Ic t and .Ic T can be used to move to the next and to the previous place providing information about the term last searched for with .Ic :t . .It Ev MANPATH The standard search path used by .Nm may be changed by specifying a path in the .Ev MANPATH environment variable. The format of the path is a colon .Pq Ql \&: separated list of directories. Invalid paths are ignored. Overridden by .Fl M , ignored if .Fl l is specified. .Pp If .Ev MANPATH begins with a colon, it is appended to the default list; if it ends with a colon, it is prepended to the default list; or if it contains two adjacent colons, the standard search path is inserted between the colons. If none of these conditions are met, it overrides the standard search path. .It Ev PAGER Specifies the pagination program to use when .Ev MANPAGER is not defined. If neither PAGER nor MANPAGER is defined, -.Xr more 1 +.Xr less 1 .Fl s is used. Only used if .Fl a or .Fl l is specified. .El .Sh FILES .Bl -tag -width /etc/man.conf -compact .It Pa /etc/man.conf default man configuration file .El .Sh EXIT STATUS .Ex -std man See .Xr mandoc 1 for details. .Sh SEE ALSO .Xr apropos 1 , .Xr intro 1 , .Xr whereis 1 , .Xr intro 2 , .Xr intro 3 , .Xr intro 4 , .Xr intro 5 , .Xr man.conf 5 , .Xr intro 6 , .Xr intro 7 , .Xr mdoc 7 , .Xr intro 8 , .Xr intro 9 .Sh STANDARDS The .Nm utility is compliant with the .St -p1003.1-2008 specification. .Pp The flags .Op Fl aCcfhIKlMmOSsTWw , as well as the environment variables .Ev MACHINE , .Ev MANPAGER , and .Ev MANPATH , are extensions to that specification. .Sh HISTORY A .Nm command first appeared in .At v3 . .Pp The .Fl w option first appeared in .At v7 ; .Fl f and .Fl k in .Bx 4 ; .Fl M in .Bx 4.3 ; .Fl a in .Bx 4.3 Tahoe ; .Fl c and .Fl m in .Bx 4.3 Reno ; .Fl h in .Bx 4.3 Net/2 ; .Fl C in .Nx 1.0 ; .Fl s and .Fl S in .Ox 2.3 ; and .Fl I , .Fl K , .Fl l , .Fl O , and .Fl W in .Ox 5.7 . The .Fl T option first appeared in .At III and was also added in .Ox 5.7 . Index: head/contrib/mdocml/mandoc.1 =================================================================== --- head/contrib/mdocml/mandoc.1 (revision 337496) +++ head/contrib/mdocml/mandoc.1 (revision 337497) @@ -1,2140 +1,2140 @@ .\" $Id: mandoc.1,v 1.217 2017/07/20 15:26:41 schwarze Exp $ .\" .\" Copyright (c) 2009, 2010, 2011 Kristaps Dzonsons .\" Copyright (c) 2012, 2014-2017 Ingo Schwarze .\" .\" 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. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES .\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF .\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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. .\" -.Dd $Mdocdate: July 20 2017 $ +.Dd $Mdocdate: August 8 2018 $ .Dt MANDOC 1 .Os .Sh NAME .Nm mandoc .Nd format manual pages .Sh SYNOPSIS .Nm mandoc .Op Fl ac .Op Fl I Cm os Ns = Ns Ar name .Op Fl K Ar encoding .Op Fl mdoc | man .Op Fl O Ar options .Op Fl T Ar output .Op Fl W Ar level .Op Ar .Sh DESCRIPTION The .Nm utility formats .Ux manual pages for display. .Pp By default, .Nm reads .Xr mdoc 7 or .Xr man 7 text from stdin and produces .Fl T Cm locale output. .Pp The options are as follows: .Bl -tag -width Ds .It Fl a If the standard output is a terminal device and .Fl c is not specified, use -.Xr more 1 +.Xr less 1 to paginate the output, just like .Xr man 1 would. .It Fl c Copy the formatted manual pages to the standard output without using -.Xr more 1 +.Xr less 1 to paginate them. This is the default. It can be specified to override .Fl a . .It Fl I Cm os Ns = Ns Ar name Override the default operating system .Ar name for the .Xr mdoc 7 .Ic \&Os and for the .Xr man 7 .Ic \&TH macro. .It Fl K Ar encoding Specify the input encoding. The supported .Ar encoding arguments are .Cm us-ascii , .Cm iso-8859-1 , and .Cm utf-8 . If not specified, autodetection uses the first match in the following list: .Bl -enum .It If the first three bytes of the input file are the UTF-8 byte order mark (BOM, 0xefbbbf), input is interpreted as .Cm utf-8 . .It If the first or second line of the input file matches the .Sy emacs mode line format .Pp .D1 .\e" -*- Oo ...; Oc coding: Ar encoding ; No -*- .Pp then input is interpreted according to .Ar encoding . .It If the first non-ASCII byte in the file introduces a valid UTF-8 sequence, input is interpreted as .Cm utf-8 . .It Otherwise, input is interpreted as .Cm iso-8859-1 . .El .It Fl mdoc | man With .Fl mdoc , all input files are interpreted as .Xr mdoc 7 . With .Fl man , all input files are interpreted as .Xr man 7 . By default, the input language is automatically detected for each file: if the the first macro is .Ic \&Dd or .Ic \&Dt , the .Xr mdoc 7 parser is used; otherwise, the .Xr man 7 parser is used. With other arguments, .Fl m is silently ignored. .It Fl O Ar options Comma-separated output options. .It Fl T Ar output Output format. See .Sx Output Formats for available formats. Defaults to .Fl T Cm locale . .It Fl W Ar level Specify the minimum message .Ar level to be reported on the standard error output and to affect the exit status. The .Ar level can be .Cm base , .Cm style , .Cm warning , .Cm error , or .Cm unsupp . The .Cm base level automatically derives the operating system from the contents of the .Ic \&Os macro, from the .Fl Ios command line option, or from the .Xr uname 3 return value. The levels .Cm openbsd and .Cm netbsd are variants of .Cm base that bypass autodetection and request validation of base system conventions for a particular operating system. The level .Cm all is an alias for .Cm base . By default, .Nm is silent. See .Sx EXIT STATUS and .Sx DIAGNOSTICS for details. .Pp The special option .Fl W Cm stop tells .Nm to exit after parsing a file that causes warnings or errors of at least the requested level. No formatted output will be produced from that file. If both a .Ar level and .Cm stop are requested, they can be joined with a comma, for example .Fl W Cm error , Ns Cm stop . .It Ar file Read input from zero or more files. If unspecified, reads from stdin. If multiple files are specified, .Nm will halt with the first failed parse. .El .Pp The options .Fl fhklw are also supported and are documented in man(1). In .Fl f and .Fl k mode, .Nm also supports the options .Fl CMmOSs described in the .Xr apropos 1 manual. The options .Fl fkl are mutually exclusive and override each other. .Ss Output Formats The .Nm utility accepts the following .Fl T arguments, which correspond to output modes: .Bl -tag -width "-T markdown" .It Fl T Cm ascii Produce 7-bit ASCII output. See .Sx ASCII Output . .It Fl T Cm html Produce HTML5, CSS1, and MathML output. See .Sx HTML Output . .It Fl T Cm lint Parse only: produce no output. Implies .Fl W Cm all and redirects parser messages, which usually appear on standard error output, to standard output. .It Fl T Cm locale Encode output using the current locale. This is the default. See .Sx Locale Output . .It Fl T Cm man Produce .Xr man 7 format output. See .Sx Man Output . .It Fl T Cm markdown Produce output in .Sy markdown format. See .Sx Markdown Output . .It Fl T Cm pdf Produce PDF output. See .Sx PDF Output . .It Fl T Cm ps Produce PostScript output. See .Sx PostScript Output . .It Fl T Cm tree Produce an indented parse tree. See .Sx Syntax tree output . .It Fl T Cm utf8 Encode output in the UTF\-8 multi-byte format. See .Sx UTF\-8 Output . .El .Pp If multiple input files are specified, these will be processed by the corresponding filter in-order. .Ss ASCII Output Output produced by .Fl T Cm ascii is rendered in standard 7-bit ASCII documented in .Xr ascii 7 . .Pp Font styles are applied by using back-spaced encoding such that an underlined character .Sq c is rendered as .Sq _ Ns \e[bs] Ns c , where .Sq \e[bs] is the back-space character number 8. Emboldened characters are rendered as .Sq c Ns \e[bs] Ns c . .Pp The special characters documented in .Xr mandoc_char 7 are rendered best-effort in an ASCII equivalent. .Pp Output width is limited to 78 visible columns unless literal input lines exceed this limit. .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm indent Ns = Ns Ar indent The left margin for normal text is set to .Ar indent blank characters instead of the default of five for .Xr mdoc 7 and seven for .Xr man 7 . Increasing this is not recommended; it may result in degraded formatting, for example overfull lines or ugly line breaks. .It Cm width Ns = Ns Ar width The output width is set to .Ar width . .El .Ss HTML Output Output produced by .Fl T Cm html conforms to HTML5 using optional self-closing tags. Default styles use only CSS1. Equations rendered from .Xr eqn 7 blocks use MathML. .Pp The .Pa mandoc.css file documents style-sheet classes available for customising output. If a style-sheet is not specified with .Fl O Cm style , .Fl T Cm html defaults to simple output (via an embedded style-sheet) readable in any graphical or text-based web browser. .Pp Special characters are rendered in decimal-encoded UTF\-8. .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm fragment Omit the declaration and the , , and elements and only emit the subtree below the element. The .Cm style argument will be ignored. This is useful when embedding manual content within existing documents. .It Cm includes Ns = Ns Ar fmt The string .Ar fmt , for example, .Ar ../src/%I.html , is used as a template for linked header files (usually via the .Ic \&In macro). Instances of .Sq \&%I are replaced with the include filename. The default is not to present a hyperlink. .It Cm man Ns = Ns Ar fmt The string .Ar fmt , for example, .Ar ../html%S/%N.%S.html , is used as a template for linked manuals (usually via the .Ic \&Xr macro). Instances of .Sq \&%N and .Sq %S are replaced with the linked manual's name and section, respectively. If no section is included, section 1 is assumed. The default is not to present a hyperlink. .It Cm style Ns = Ns Ar style.css The file .Ar style.css is used for an external style-sheet. This must be a valid absolute or relative URI. .El .Ss Locale Output Locale-depending output encoding is triggered with .Fl T Cm locale . This is the default. .Pp This option is not available on all systems: systems without locale support, or those whose internal representation is not natively UCS-4, will fall back to .Fl T Cm ascii . See .Sx ASCII Output for font style specification and available command-line arguments. .Ss Man Output Translate input format into .Xr man 7 output format. This is useful for distributing manual sources to legacy systems lacking .Xr mdoc 7 formatters. .Pp If .Xr mdoc 7 is passed as input, it is translated into .Xr man 7 . If the input format is .Xr man 7 , the input is copied to the output, expanding any .Xr roff 7 .Ic so requests. The parser is also run, and as usual, the .Fl W level controls which .Sx DIAGNOSTICS are displayed before copying the input to the output. .Ss Markdown Output Translate .Xr mdoc 7 input to the .Sy markdown format conforming to .Lk http://daringfireball.net/projects/markdown/syntax.text\ "John Gruber's 2004 specification" . The output also almost conforms to the .Lk http://commonmark.org/ CommonMark specification. .Pp The character set used for the markdown output is ASCII. Non-ASCII characters are encoded as HTML entities. Since that is not possible in literal font contexts, because these are rendered as code spans and code blocks in the markdown output, non-ASCII characters are transliterated to ASCII approximations in these contexts. .Pp Markdown is a very weak markup language, so all semantic markup is lost, and even part of the presentational markup may be lost. Do not use this as an intermediate step in converting to HTML; instead, use .Fl T Cm html directly. .Pp The .Xr man 7 , .Xr tbl 7 , and .Xr eqn 7 input languages are not supported by .Fl T Cm markdown output mode. .Ss PDF Output PDF-1.1 output may be generated by .Fl T Cm pdf . See .Sx PostScript Output for .Fl O arguments and defaults. .Ss PostScript Output PostScript .Qq Adobe-3.0 Level-2 pages may be generated by .Fl T Cm ps . Output pages default to letter sized and are rendered in the Times font family, 11-point. Margins are calculated as 1/9 the page length and width. Line-height is 1.4m. .Pp Special characters are rendered as in .Sx ASCII Output . .Pp The following .Fl O arguments are accepted: .Bl -tag -width Ds .It Cm paper Ns = Ns Ar name The paper size .Ar name may be one of .Ar a3 , .Ar a4 , .Ar a5 , .Ar legal , or .Ar letter . You may also manually specify dimensions as .Ar NNxNN , width by height in millimetres. If an unknown value is encountered, .Ar letter is used. .El .Ss UTF\-8 Output Use .Fl T Cm utf8 to force a UTF\-8 locale. See .Sx Locale Output for details and options. .Ss Syntax tree output Use .Fl T Cm tree to show a human readable representation of the syntax tree. It is useful for debugging the source code of manual pages. The exact format is subject to change, so don't write parsers for it. .Pp The first paragraph shows meta data found in the .Xr mdoc 7 prologue, on the .Xr man 7 .Ic \&TH line, or the fallbacks used. .Pp In the tree dump, each output line shows one syntax tree node. Child nodes are indented with respect to their parent node. The columns are: .Pp .Bl -enum -compact .It For macro nodes, the macro name; for text and .Xr tbl 7 nodes, the content. There is a special format for .Xr eqn 7 nodes. .It Node type (text, elem, block, head, body, body-end, tail, tbl, eqn). .It Flags: .Bl -dash -compact .It An opening parenthesis if the node is an opening delimiter. .It An asterisk if the node starts a new input line. .It The input line number (starting at one). .It A colon. .It The input column number (starting at one). .It A closing parenthesis if the node is a closing delimiter. .It A full stop if the node ends a sentence. .It BROKEN if the node is a block broken by another block. .It NOSRC if the node is not in the input file, but automatically generated from macros. .It NOPRT if the node is not supposed to generate output for any output format. .El .El .Pp The following .Fl O argument is accepted: .Bl -tag -width Ds .It Cm noval Skip validation and show the unvalidated syntax tree. This can help to find out whether a given behaviour is caused by the parser or by the validator. Meta data is not available in this case. .El .Sh ENVIRONMENT .Bl -tag -width MANPAGER .It Ev MANPAGER Any non-empty value of the environment variable .Ev MANPAGER is used instead of the standard pagination program, -.Xr more 1 ; +.Xr less 1 ; see .Xr man 1 for details. Only used if .Fl a or .Fl l is specified. .It Ev PAGER Specifies the pagination program to use when .Ev MANPAGER is not defined. If neither PAGER nor MANPAGER is defined, -.Xr more 1 +.Xr less 1 .Fl s is used. Only used if .Fl a or .Fl l is specified. .El .Sh EXIT STATUS The .Nm utility exits with one of the following values, controlled by the message .Ar level associated with the .Fl W option: .Pp .Bl -tag -width Ds -compact .It 0 No base system convention violations, style suggestions, warnings, or errors occurred, or those that did were ignored because they were lower than the requested .Ar level . .It 1 At least one base system convention violation or style suggestion occurred, but no warning or error, and .Fl W Cm base or .Fl W Cm style was specified. .It 2 At least one warning occurred, but no error, and .Fl W Cm warning or a lower .Ar level was requested. .It 3 At least one parsing error occurred, but no unsupported feature was encountered, and .Fl W Cm error or a lower .Ar level was requested. .It 4 At least one unsupported feature was encountered, and .Fl W Cm unsupp or a lower .Ar level was requested. .It 5 Invalid command line arguments were specified. No input files have been read. .It 6 An operating system error occurred, for example exhaustion of memory, file descriptors, or process table entries. Such errors cause .Nm to exit at once, possibly in the middle of parsing or formatting a file. .El .Pp Note that selecting .Fl T Cm lint output mode implies .Fl W Cm all . .Sh EXAMPLES To page manuals to the terminal: .Pp .Dl $ mandoc -l mandoc.1 man.1 apropos.1 makewhatis.8 .Pp To produce HTML manuals with .Pa mandoc.css as the style-sheet: .Pp .Dl $ mandoc \-T html -O style=mandoc.css mdoc.7 \*(Gt mdoc.7.html .Pp To check over a large set of manuals: .Pp .Dl $ mandoc \-T lint \(gafind /usr/src -name \e*\e.[1-9]\(ga .Pp To produce a series of PostScript manuals for A4 paper: .Pp .Dl $ mandoc \-T ps \-O paper=a4 mdoc.7 man.7 \*(Gt manuals.ps .Pp Convert a modern .Xr mdoc 7 manual to the older .Xr man 7 format, for use on systems lacking an .Xr mdoc 7 parser: .Pp .Dl $ mandoc \-T man foo.mdoc \*(Gt foo.man .Sh DIAGNOSTICS Messages displayed by .Nm follow this format: .Bd -ragged -offset indent .Nm : .Ar file : Ns Ar line : Ns Ar column : level : message : macro args .Pq Ar os .Ed .Pp Line and column numbers start at 1. Both are omitted for messages referring to an input file as a whole. Macro names and arguments are omitted where meaningless. The .Ar os operating system specifier is omitted for messages that are relevant for all operating systems. Fatal messages about invalid command line arguments or operating system errors, for example when memory is exhausted, may also omit the .Ar file and .Ar level fields. .Pp Message levels have the following meanings: .Bl -tag -width "warning" .It Cm unsupp An input file uses unsupported low-level .Xr roff 7 features. The output may be incomplete and/or misformatted, so using GNU troff instead of .Nm to process the file may be preferable. .It Cm error Indicates a risk of information loss or severe misformatting, in most cases caused by serious syntax errors. .It Cm warning Indicates a risk that the information shown or its formatting may mismatch the author's intent in minor ways. Additionally, syntax errors are classified at least as warnings, even if they do not usually cause misformatting. .It Cm style An input file uses dubious or discouraged style. This is not a complaint about the syntax, and probably neither formatting nor portability are in danger. While great care is taken to avoid false positives on the higher message levels, the .Cm style level tries to reduce the probability that issues go unnoticed, so it may occasionally issue bogus suggestions. Please use your good judgement to decide whether any particular .Cm style suggestion really justifies a change to the input file. .It Cm base A convertion used in the base system of a specific operating system is not adhered to. These are not markup mistakes, and neither the quality of formatting nor portability are in danger. Messages of the .Cm base level are printed with the more intuitive .Cm style .Ar level tag. .El .Pp Messages of the .Cm base , .Cm style , .Cm warning , .Cm error , and .Cm unsupp levels except those about non-existent or unreadable input files are hidden unless their level, or a lower level, is requested using a .Fl W option or .Fl T Cm lint output mode. .Pp As indicated below, all .Cm base and some .Cm style checks are only performed if a specific operating system name occurs in the arguments of the .Fl W command line option, of the .Ic \&Os macro, of the .Fl Ios command line option, or, if neither are present, in the return value of the .Xr uname 3 function. .Ss Conventions for base system manuals .Bl -ohang .It Sy "Mdocdate found" .Pq mdoc , Nx The .Ic \&Dd macro uses CVS .Ic Mdocdate keyword substitution, which is not supported by the .Nx base system. Consider using the conventional .Dq "Month dd, yyyy" format instead. .It Sy "Mdocdate missing" .Pq mdoc , Ox The .Ic \&Dd macro does not use CVS .Ic Mdocdate keyword substitution, but using it is conventionally expected in the .Ox base system. .It Sy "unknown architecture" .Pq mdoc , Ox , Nx The third argument of the .Ic \&Dt macro does not match any of the architectures this operating system is running on. .It Sy "operating system explicitly specified" .Pq mdoc , Ox , Nx The .Ic \&Os macro has an argument. In the base system, it is conventionally left blank. .It Sy "RCS id missing" .Pq Ox , Nx The manual page lacks the comment line with the RCS identifier generated by CVS .Ic OpenBSD or .Ic NetBSD keyword substitution as conventionally used in these operating systems. .It Sy "referenced manual not found" .Pq mdoc An .Ic \&Xr macro references a manual page that is not found in the base system. The path to look for base system manuals is configurable at compile time and defaults to .Pa /usr/share/man : /usr/X11R6/man . .El .Ss Style suggestions .Bl -ohang .It Sy "legacy man(7) date format" .Pq mdoc The .Ic \&Dd macro uses the legacy .Xr man 7 date format .Dq yyyy-dd-mm . Consider using the conventional .Xr mdoc 7 date format .Dq "Month dd, yyyy" instead. .It Sy "lower case character in document title" .Pq mdoc , man The title is still used as given in the .Ic \&Dt or .Ic \&TH macro. .It Sy "duplicate RCS id" A single manual page contains two copies of the RCS identifier for the same operating system. Consider deleting the later instance and moving the first one up to the top of the page. .It Sy "typo in section name" .Pq mdoc Fuzzy string matching revealed that the argument of an .Ic \&Sh macro is similar, but not identical to a standard section name. .It Sy "unterminated quoted argument" .Pq roff Macro arguments can be enclosed in double quote characters such that space characters and macro names contained in the quoted argument need not be escaped. The closing quote of the last argument of a macro can be omitted. However, omitting it is not recommended because it makes the code harder to read. .It Sy "useless macro" .Pq mdoc A .Ic \&Bt , .Ic \&Tn , or .Ic \&Ud macro was found. Simply delete it: it serves no useful purpose. .It Sy "consider using OS macro" .Pq mdoc A string was found in plain text or in a .Ic \&Bx macro that could be represented using .Ic \&Ox , .Ic \&Nx , .Ic \&Fx , or .Ic \&Dx . .It Sy "errnos out of order" .Pq mdoc, Nx The .Ic \&Er items in a .Ic \&Bl list are not in alphabetical order. .It Sy "duplicate errno" .Pq mdoc, Nx A .Ic \&Bl list contains two consecutive .Ic \&It entries describing the same .Ic \&Er number. .It Sy "trailing delimiter" .Pq mdoc The last argument of an .Ic \&Ex , \&Fo , \&Nd , \&Nm , \&Os , \&Sh , \&Ss , \&St , or .Ic \&Sx macro ends with a trailing delimiter. This is usually bad style and often indicates typos. Most likely, the delimiter can be removed. .It Sy "no blank before trailing delimiter" .Pq mdoc The last argument of a macro that supports trailing delimiter arguments is longer than one byte and ends with a trailing delimiter. Consider inserting a blank such that the delimiter becomes a separate argument, thus moving it out of the scope of the macro. .It Sy "fill mode already enabled, skipping" .Pq man A .Ic \&fi request occurs even though the document is still in fill mode, or already switched back to fill mode. It has no effect. .It Sy "fill mode already disabled, skipping" .Pq man An .Ic \&nf request occurs even though the document already switched to no-fill mode and did not switch back to fill mode yet. It has no effect. .It Sy "function name without markup" .Pq mdoc A word followed by an empty pair of parentheses occurs on a text line. Consider using an .Ic \&Fn or .Ic \&Xr macro. .It Sy "whitespace at end of input line" .Pq mdoc , man , roff Whitespace at the end of input lines is almost never semantically significant \(em but in the odd case where it might be, it is extremely confusing when reviewing and maintaining documents. .It Sy "bad comment style" .Pq roff Comment lines start with a dot, a backslash, and a double-quote character. The .Nm utility treats the line as a comment line even without the backslash, but leaving out the backslash might not be portable. .El .Ss Warnings related to the document prologue .Bl -ohang .It Sy "missing manual title, using UNTITLED" .Pq mdoc A .Ic \&Dt macro has no arguments, or there is no .Ic \&Dt macro before the first non-prologue macro. .It Sy "missing manual title, using \(dq\(dq" .Pq man There is no .Ic \&TH macro, or it has no arguments. .It Sy "missing manual section, using \(dq\(dq" .Pq mdoc , man A .Ic \&Dt or .Ic \&TH macro lacks the mandatory section argument. .It Sy "unknown manual section" .Pq mdoc The section number in a .Ic \&Dt line is invalid, but still used. .It Sy "missing date, using today's date" .Pq mdoc, man The document was parsed as .Xr mdoc 7 and it has no .Ic \&Dd macro, or the .Ic \&Dd macro has no arguments or only empty arguments; or the document was parsed as .Xr man 7 and it has no .Ic \&TH macro, or the .Ic \&TH macro has less than three arguments or its third argument is empty. .It Sy "cannot parse date, using it verbatim" .Pq mdoc , man The date given in a .Ic \&Dd or .Ic \&TH macro does not follow the conventional format. .It Sy "date in the future, using it anyway" .Pq mdoc , man The date given in a .Ic \&Dd or .Ic \&TH macro is more than a day ahead of the current system .Xr time 3 . .It Sy "missing Os macro, using \(dq\(dq" .Pq mdoc The default or current system is not shown in this case. .It Sy "late prologue macro" .Pq mdoc A .Ic \&Dd or .Ic \&Os macro occurs after some non-prologue macro, but still takes effect. .It Sy "prologue macros out of order" .Pq mdoc The prologue macros are not given in the conventional order .Ic \&Dd , .Ic \&Dt , .Ic \&Os . All three macros are used even when given in another order. .El .Ss Warnings regarding document structure .Bl -ohang .It Sy ".so is fragile, better use ln(1)" .Pq roff Including files only works when the parser program runs with the correct current working directory. .It Sy "no document body" .Pq mdoc , man The document body contains neither text nor macros. An empty document is shown, consisting only of a header and a footer line. .It Sy "content before first section header" .Pq mdoc , man Some macros or text precede the first .Ic \&Sh or .Ic \&SH section header. The offending macros and text are parsed and added to the top level of the syntax tree, outside any section block. .It Sy "first section is not NAME" .Pq mdoc The argument of the first .Ic \&Sh macro is not .Sq NAME . This may confuse .Xr makewhatis 8 and .Xr apropos 1 . .It Sy "NAME section without Nm before Nd" .Pq mdoc The NAME section does not contain any .Ic \&Nm child macro before the first .Ic \&Nd macro. .It Sy "NAME section without description" .Pq mdoc The NAME section lacks the mandatory .Ic \&Nd child macro. .It Sy "description not at the end of NAME" .Pq mdoc The NAME section does contain an .Ic \&Nd child macro, but other content follows it. .It Sy "bad NAME section content" .Pq mdoc The NAME section contains plain text or macros other than .Ic \&Nm and .Ic \&Nd . .It Sy "missing comma before name" .Pq mdoc The NAME section contains an .Ic \&Nm macro that is neither the first one nor preceded by a comma. .It Sy "missing description line, using \(dq\(dq" .Pq mdoc The .Ic \&Nd macro lacks the required argument. The title line of the manual will end after the dash. .It Sy "description line outside NAME section" .Pq mdoc An .Ic \&Nd macro appears outside the NAME section. The arguments are printed anyway and the following text is used for .Xr apropos 1 , but none of that behaviour is portable. .It Sy "sections out of conventional order" .Pq mdoc A standard section occurs after another section it usually precedes. All section titles are used as given, and the order of sections is not changed. .It Sy "duplicate section title" .Pq mdoc The same standard section title occurs more than once. .It Sy "unexpected section" .Pq mdoc A standard section header occurs in a section of the manual where it normally isn't useful. .It Sy "cross reference to self" .Pq mdoc An .Ic \&Xr macro refers to a name and section matching the section of the present manual page and a name mentioned in an .Ic \&Nm macro in the NAME or SYNOPSIS section, or in an .Ic \&Fn or .Ic \&Fo macro in the SYNOPSIS. Consider using .Ic \&Nm or .Ic \&Fn instead of .Ic \&Xr . .It Sy "unusual Xr order" .Pq mdoc In the SEE ALSO section, an .Ic \&Xr macro with a lower section number follows one with a higher number, or two .Ic \&Xr macros referring to the same section are out of alphabetical order. .It Sy "unusual Xr punctuation" .Pq mdoc In the SEE ALSO section, punctuation between two .Ic \&Xr macros differs from a single comma, or there is trailing punctuation after the last .Ic \&Xr macro. .It Sy "AUTHORS section without An macro" .Pq mdoc An AUTHORS sections contains no .Ic \&An macros, or only empty ones. Probably, there are author names lacking markup. .El .Ss "Warnings related to macros and nesting" .Bl -ohang .It Sy "obsolete macro" .Pq mdoc See the .Xr mdoc 7 manual for replacements. .It Sy "macro neither callable nor escaped" .Pq mdoc The name of a macro that is not callable appears on a macro line. It is printed verbatim. If the intention is to call it, move it to its own input line; otherwise, escape it by prepending .Sq \e& . .It Sy "skipping paragraph macro" In .Xr mdoc 7 documents, this happens .Bl -dash -compact .It at the beginning and end of sections and subsections .It right before non-compact lists and displays .It at the end of items in non-column, non-compact lists .It and for multiple consecutive paragraph macros. .El In .Xr man 7 documents, it happens .Bl -dash -compact .It for empty .Ic \&P , .Ic \&PP , and .Ic \&LP macros .It for .Ic \&IP macros having neither head nor body arguments .It for .Ic \&br or .Ic \&sp right after .Ic \&SH or .Ic \&SS .El .It Sy "moving paragraph macro out of list" .Pq mdoc A list item in a .Ic \&Bl list contains a trailing paragraph macro. The paragraph macro is moved after the end of the list. .It Sy "skipping no-space macro" .Pq mdoc An input line begins with an .Ic \&Ns macro, or the next argument after an .Ic \&Ns macro is an isolated closing delimiter. The macro is ignored. .It Sy "blocks badly nested" .Pq mdoc If two blocks intersect, one should completely contain the other. Otherwise, rendered output is likely to look strange in any output format, and rendering in SGML-based output formats is likely to be outright wrong because such languages do not support badly nested blocks at all. Typical examples of badly nested blocks are .Qq Ic \&Ao \&Bo \&Ac \&Bc and .Qq Ic \&Ao \&Bq \&Ac . In these examples, .Ic \&Ac breaks .Ic \&Bo and .Ic \&Bq , respectively. .It Sy "nested displays are not portable" .Pq mdoc A .Ic \&Bd , .Ic \&D1 , or .Ic \&Dl display occurs nested inside another .Ic \&Bd display. This works with .Nm , but fails with most other implementations. .It Sy "moving content out of list" .Pq mdoc A .Ic \&Bl list block contains text or macros before the first .Ic \&It macro. The offending children are moved before the beginning of the list. .It Sy "first macro on line" Inside a .Ic \&Bl Fl column list, a .Ic \&Ta macro occurs as the first macro on a line, which is not portable. .It Sy "line scope broken" .Pq man While parsing the next-line scope of the previous macro, another macro is found that prematurely terminates the previous one. The previous, interrupted macro is deleted from the parse tree. .El .Ss "Warnings related to missing arguments" .Bl -ohang .It Sy "skipping empty request" .Pq roff , eqn The macro name is missing from a macro definition request, or an .Xr eqn 7 control statement or operation keyword lacks its required argument. .It Sy "conditional request controls empty scope" .Pq roff A conditional request is only useful if any of the following follows it on the same logical input line: .Bl -dash -compact .It The .Sq \e{ keyword to open a multi-line scope. .It A request or macro or some text, resulting in a single-line scope. .It The immediate end of the logical line without any intervening whitespace, resulting in next-line scope. .El Here, a conditional request is followed by trailing whitespace only, and there is no other content on its logical input line. Note that it doesn't matter whether the logical input line is split across multiple physical input lines using .Sq \e line continuation characters. This is one of the rare cases where trailing whitespace is syntactically significant. The conditional request controls a scope containing whitespace only, so it is unlikely to have a significant effect, except that it may control a following .Ic \&el clause. .It Sy "skipping empty macro" .Pq mdoc The indicated macro has no arguments and hence no effect. .It Sy "empty block" .Pq mdoc , man A .Ic \&Bd , .Ic \&Bk , .Ic \&Bl , .Ic \&D1 , .Ic \&Dl , .Ic \&MT , .Ic \&RS , or .Ic \&UR block contains nothing in its body and will produce no output. .It Sy "empty argument, using 0n" .Pq mdoc The required width is missing after .Ic \&Bd or .Ic \&Bl .Fl offset or .Fl width . .It Sy "missing display type, using -ragged" .Pq mdoc The .Ic \&Bd macro is invoked without the required display type. .It Sy "list type is not the first argument" .Pq mdoc In a .Ic \&Bl macro, at least one other argument precedes the type argument. The .Nm utility copes with any argument order, but some other .Xr mdoc 7 implementations do not. .It Sy "missing -width in -tag list, using 8n" .Pq mdoc Every .Ic \&Bl macro having the .Fl tag argument requires .Fl width , too. .It Sy "missing utility name, using \(dq\(dq" .Pq mdoc The .Ic \&Ex Fl std macro is called without an argument before .Ic \&Nm has first been called with an argument. .It Sy "missing function name, using \(dq\(dq" .Pq mdoc The .Ic \&Fo macro is called without an argument. No function name is printed. .It Sy "empty head in list item" .Pq mdoc In a .Ic \&Bl .Fl diag , .Fl hang , .Fl inset , .Fl ohang , or .Fl tag list, an .Ic \&It macro lacks the required argument. The item head is left empty. .It Sy "empty list item" .Pq mdoc In a .Ic \&Bl .Fl bullet , .Fl dash , .Fl enum , or .Fl hyphen list, an .Ic \&It block is empty. An empty list item is shown. .It Sy "missing argument, using next line" .Pq mdoc An .Ic \&It macro in a .Ic \&Bd Fl column list has no arguments. While .Nm uses the text or macros of the following line, if any, for the cell, other formatters may misformat the list. .It Sy "missing font type, using \efR" .Pq mdoc A .Ic \&Bf macro has no argument. It switches to the default font. .It Sy "unknown font type, using \efR" .Pq mdoc The .Ic \&Bf argument is invalid. The default font is used instead. .It Sy "nothing follows prefix" .Pq mdoc A .Ic \&Pf macro has no argument, or only one argument and no macro follows on the same input line. This defeats its purpose; in particular, spacing is not suppressed before the text or macros following on the next input line. .It Sy "empty reference block" .Pq mdoc An .Ic \&Rs macro is immediately followed by an .Ic \&Re macro on the next input line. Such an empty block does not produce any output. .It Sy "missing section argument" .Pq mdoc An .Ic \&Xr macro lacks its second, section number argument. The first argument, i.e. the name, is printed, but without subsequent parentheses. .It Sy "missing -std argument, adding it" .Pq mdoc An .Ic \&Ex or .Ic \&Rv macro lacks the required .Fl std argument. The .Nm utility assumes .Fl std even when it is not specified, but other implementations may not. .It Sy "missing option string, using \(dq\(dq" .Pq man The .Ic \&OP macro is invoked without any argument. An empty pair of square brackets is shown. .It Sy "missing resource identifier, using \(dq\(dq" .Pq man The .Ic \&MT or .Ic \&UR macro is invoked without any argument. An empty pair of angle brackets is shown. .It Sy "missing eqn box, using \(dq\(dq" .Pq eqn A diacritic mark or a binary operator is found, but there is nothing to the left of it. An empty box is inserted. .El .Ss "Warnings related to bad macro arguments" .Bl -ohang .It Sy "duplicate argument" .Pq mdoc A .Ic \&Bd or .Ic \&Bl macro has more than one .Fl compact , more than one .Fl offset , or more than one .Fl width argument. All but the last instances of these arguments are ignored. .It Sy "skipping duplicate argument" .Pq mdoc An .Ic \&An macro has more than one .Fl split or .Fl nosplit argument. All but the first of these arguments are ignored. .It Sy "skipping duplicate display type" .Pq mdoc A .Ic \&Bd macro has more than one type argument; the first one is used. .It Sy "skipping duplicate list type" .Pq mdoc A .Ic \&Bl macro has more than one type argument; the first one is used. .It Sy "skipping -width argument" .Pq mdoc A .Ic \&Bl .Fl column , .Fl diag , .Fl ohang , .Fl inset , or .Fl item list has a .Fl width argument. That has no effect. .It Sy "wrong number of cells" In a line of a .Ic \&Bl Fl column list, the number of tabs or .Ic \&Ta macros is less than the number expected from the list header line or exceeds the expected number by more than one. Missing cells remain empty, and all cells exceeding the number of columns are joined into one single cell. .It Sy "unknown AT&T UNIX version" .Pq mdoc An .Ic \&At macro has an invalid argument. It is used verbatim, with .Qq "AT&T UNIX " prefixed to it. .It Sy "comma in function argument" .Pq mdoc An argument of an .Ic \&Fa or .Ic \&Fn macro contains a comma; it should probably be split into two arguments. .It Sy "parenthesis in function name" .Pq mdoc The first argument of an .Ic \&Fc or .Ic \&Fn macro contains an opening or closing parenthesis; that's probably wrong, parentheses are added automatically. .It Sy "unknown library name" .Pq mdoc, not on Ox An .Ic \&Lb macro has an unknown name argument and will be rendered as .Qq library Dq Ar name . .It Sy "invalid content in Rs block" .Pq mdoc An .Ic \&Rs block contains plain text or non-% macros. The bogus content is left in the syntax tree. Formatting may be poor. .It Sy "invalid Boolean argument" .Pq mdoc An .Ic \&Sm macro has an argument other than .Cm on or .Cm off . The invalid argument is moved out of the macro, which leaves the macro empty, causing it to toggle the spacing mode. .It Sy "unknown font, skipping request" .Pq man , tbl A .Xr roff 7 .Ic \&ft request or a .Xr tbl 7 .Ic \&f layout modifier has an unknown .Ar font argument. .It Sy "odd number of characters in request" .Pq roff A .Ic \&tr request contains an odd number of characters. The last character is mapped to the blank character. .El .Ss "Warnings related to plain text" .Bl -ohang .It Sy "blank line in fill mode, using .sp" .Pq mdoc The meaning of blank input lines is only well-defined in non-fill mode: In fill mode, line breaks of text input lines are not supposed to be significant. However, for compatibility with groff, blank lines in fill mode are replaced with .Ic \&sp requests. .It Sy "tab in filled text" .Pq mdoc , man The meaning of tab characters is only well-defined in non-fill mode: In fill mode, whitespace is not supposed to be significant on text input lines. As an implementation dependent choice, tab characters on text lines are passed through to the formatters in any case. Given that the text before the tab character will be filled, it is hard to predict which tab stop position the tab will advance to. .It Sy "new sentence, new line" .Pq mdoc A new sentence starts in the middle of a text line. Start it on a new input line to help formatters produce correct spacing. .It Sy "invalid escape sequence" .Pq roff An escape sequence has an invalid opening argument delimiter, lacks the closing argument delimiter, or the argument has too few characters. If the argument is incomplete, .Ic \e* and .Ic \en expand to an empty string, .Ic \eB to the digit .Sq 0 , and .Ic \ew to the length of the incomplete argument. All other invalid escape sequences are ignored. .It Sy "undefined string, using \(dq\(dq" .Pq roff If a string is used without being defined before, its value is implicitly set to the empty string. However, defining strings explicitly before use keeps the code more readable. .El .Ss "Warnings related to tables" .Bl -ohang .It Sy "tbl line starts with span" .Pq tbl The first cell in a table layout line is a horizontal span .Pq Sq Cm s . Data provided for this cell is ignored, and nothing is printed in the cell. .It Sy "tbl column starts with span" .Pq tbl The first line of a table layout specification requests a vertical span .Pq Sq Cm ^ . Data provided for this cell is ignored, and nothing is printed in the cell. .It Sy "skipping vertical bar in tbl layout" .Pq tbl A table layout specification contains more than two consecutive vertical bars. A double bar is printed, all additional bars are discarded. .El .Ss "Errors related to tables" .Bl -ohang .It Sy "non-alphabetic character in tbl options" .Pq tbl The table options line contains a character other than a letter, blank, or comma where the beginning of an option name is expected. The character is ignored. .It Sy "skipping unknown tbl option" .Pq tbl The table options line contains a string of letters that does not match any known option name. The word is ignored. .It Sy "missing tbl option argument" .Pq tbl A table option that requires an argument is not followed by an opening parenthesis, or the opening parenthesis is immediately followed by a closing parenthesis. The option is ignored. .It Sy "wrong tbl option argument size" .Pq tbl A table option argument contains an invalid number of characters. Both the option and the argument are ignored. .It Sy "empty tbl layout" .Pq tbl A table layout specification is completely empty, specifying zero lines and zero columns. As a fallback, a single left-justified column is used. .It Sy "invalid character in tbl layout" .Pq tbl A table layout specification contains a character that can neither be interpreted as a layout key character nor as a layout modifier, or a modifier precedes the first key. The invalid character is discarded. .It Sy "unmatched parenthesis in tbl layout" .Pq tbl A table layout specification contains an opening parenthesis, but no matching closing parenthesis. The rest of the input line, starting from the parenthesis, has no effect. .It Sy "tbl without any data cells" .Pq tbl A table does not contain any data cells. It will probably produce no output. .It Sy "ignoring data in spanned tbl cell" .Pq tbl A table cell is marked as a horizontal span .Pq Sq Cm s or vertical span .Pq Sq Cm ^ in the table layout, but it contains data. The data is ignored. .It Sy "ignoring extra tbl data cells" .Pq tbl A data line contains more cells than the corresponding layout line. The data in the extra cells is ignored. .It Sy "data block open at end of tbl" .Pq tbl A data block is opened with .Cm T{ , but never closed with a matching .Cm T} . The remaining data lines of the table are all put into one cell, and any remaining cells stay empty. .El .Ss "Errors related to roff, mdoc, and man code" .Bl -ohang .It Sy "duplicate prologue macro" .Pq mdoc One of the prologue macros occurs more than once. The last instance overrides all previous ones. .It Sy "skipping late title macro" .Pq mdoc The .Ic \&Dt macro appears after the first non-prologue macro. Traditional formatters cannot handle this because they write the page header before parsing the document body. Even though this technical restriction does not apply to .Nm , traditional semantics is preserved. The late macro is discarded including its arguments. .It Sy "input stack limit exceeded, infinite loop?" .Pq roff Explicit recursion limits are implemented for the following features, in order to prevent infinite loops: .Bl -dash -compact .It expansion of nested escape sequences including expansion of strings and number registers, .It expansion of nested user-defined macros, .It and .Ic \&so file inclusion. .El When a limit is hit, the output is incorrect, typically losing some content, but the parser can continue. .It Sy "skipping bad character" .Pq mdoc , man , roff The input file contains a byte that is not a printable .Xr ascii 7 character. The message mentions the character number. The offending byte is replaced with a question mark .Pq Sq \&? . Consider editing the input file to replace the byte with an ASCII transliteration of the intended character. .It Sy "skipping unknown macro" .Pq mdoc , man , roff The first identifier on a request or macro line is neither recognized as a .Xr roff 7 request, nor as a user-defined macro, nor, respectively, as an .Xr mdoc 7 or .Xr man 7 macro. It may be mistyped or unsupported. The request or macro is discarded including its arguments. .It Sy "skipping insecure request" .Pq roff An input file attempted to run a shell command or to read or write an external file. Such attempts are denied for security reasons. .It Sy "skipping item outside list" .Pq mdoc , eqn An .Ic \&It macro occurs outside any .Ic \&Bl list, or an .Xr eqn 7 .Ic above delimiter occurs outside any pile. It is discarded including its arguments. .It Sy "skipping column outside column list" .Pq mdoc A .Ic \&Ta macro occurs outside any .Ic \&Bl Fl column block. It is discarded including its arguments. .It Sy "skipping end of block that is not open" .Pq mdoc , man , eqn , tbl , roff Various syntax elements can only be used to explicitly close blocks that have previously been opened. An .Xr mdoc 7 block closing macro, a .Xr man 7 .Ic \&ME , \&RE or .Ic \&UE macro, an .Xr eqn 7 right delimiter or closing brace, or the end of an equation, table, or .Xr roff 7 conditional request is encountered but no matching block is open. The offending request or macro is discarded. .It Sy "fewer RS blocks open, skipping" .Pq man The .Ic \&RE macro is invoked with an argument, but less than the specified number of .Ic \&RS blocks is open. The .Ic \&RE macro is discarded. .It Sy "inserting missing end of block" .Pq mdoc , tbl Various .Xr mdoc 7 macros as well as tables require explicit closing by dedicated macros. A block that doesn't support bad nesting ends before all of its children are properly closed. The open child nodes are closed implicitly. .It Sy "appending missing end of block" .Pq mdoc , man , eqn , tbl , roff At the end of the document, an explicit .Xr mdoc 7 block, a .Xr man 7 next-line scope or .Ic \&MT , \&RS or .Ic \&UR block, an equation, table, or .Xr roff 7 conditional or ignore block is still open. The open block is closed implicitly. .It Sy "escaped character not allowed in a name" .Pq roff Macro, string and register identifiers consist of printable, non-whitespace ASCII characters. Escape sequences and characters and strings expressed in terms of them cannot form part of a name. The first argument of an .Ic \&am , .Ic \&as , .Ic \&de , .Ic \&ds , .Ic \&nr , or .Ic \&rr request, or any argument of an .Ic \&rm request, or the name of a request or user defined macro being called, is terminated by an escape sequence. In the cases of .Ic \&as , .Ic \&ds , and .Ic \&nr , the request has no effect at all. In the cases of .Ic \&am , .Ic \&de , .Ic \&rr , and .Ic \&rm , what was parsed up to this point is used as the arguments to the request, and the rest of the input line is discarded including the escape sequence. When parsing for a request or a user-defined macro name to be called, only the escape sequence is discarded. The characters preceding it are used as the request or macro name, the characters following it are used as the arguments to the request or macro. .It Sy "NOT IMPLEMENTED: Bd -file" .Pq mdoc For security reasons, the .Ic \&Bd macro does not support the .Fl file argument. By requesting the inclusion of a sensitive file, a malicious document might otherwise trick a privileged user into inadvertently displaying the file on the screen, revealing the file content to bystanders. The argument is ignored including the file name following it. .It Sy "skipping display without arguments" .Pq mdoc A .Ic \&Bd block macro does not have any arguments. The block is discarded, and the block content is displayed in whatever mode was active before the block. .It Sy "missing list type, using -item" .Pq mdoc A .Ic \&Bl macro fails to specify the list type. .It Sy "argument is not numeric, using 1" .Pq roff The argument of a .Ic \&ce request is not a number. .It Sy "missing manual name, using \(dq\(dq" .Pq mdoc The first call to .Ic \&Nm , or any call in the NAME section, lacks the required argument. .It Sy "uname(3) system call failed, using UNKNOWN" .Pq mdoc The .Ic \&Os macro is called without arguments, and the .Xr uname 3 system call failed. As a workaround, .Nm can be compiled with .Sm off .Fl D Cm OSNAME=\(dq\e\(dq Ar string Cm \e\(dq\(dq . .Sm on .It Sy "unknown standard specifier" .Pq mdoc An .Ic \&St macro has an unknown argument and is discarded. .It Sy "skipping request without numeric argument" .Pq roff , eqn An .Ic \&it request or an .Xr eqn 7 .Ic \&size or .Ic \&gsize statement has a non-numeric or negative argument or no argument at all. The invalid request or statement is ignored. .It Sy "NOT IMPLEMENTED: .so with absolute path or \(dq..\(dq" .Pq roff For security reasons, .Nm allows .Ic \&so file inclusion requests only with relative paths and only without ascending to any parent directory. By requesting the inclusion of a sensitive file, a malicious document might otherwise trick a privileged user into inadvertently displaying the file on the screen, revealing the file content to bystanders. .Nm only shows the path as it appears behind .Ic \&so . .It Sy ".so request failed" .Pq roff Servicing a .Ic \&so request requires reading an external file, but the file could not be opened. .Nm only shows the path as it appears behind .Ic \&so . .It Sy "skipping all arguments" .Pq mdoc , man , eqn , roff An .Xr mdoc 7 .Ic \&Bt , .Ic \&Ed , .Ic \&Ef , .Ic \&Ek , .Ic \&El , .Ic \&Lp , .Ic \&Pp , .Ic \&Re , .Ic \&Rs , or .Ic \&Ud macro, an .Ic \&It macro in a list that don't support item heads, a .Xr man 7 .Ic \&LP , .Ic \&P , or .Ic \&PP macro, an .Xr eqn 7 .Ic \&EQ or .Ic \&EN macro, or a .Xr roff 7 .Ic \&br , .Ic \&fi , or .Ic \&nf request or .Sq \&.. block closing request is invoked with at least one argument. All arguments are ignored. .It Sy "skipping excess arguments" .Pq mdoc , man , roff A macro or request is invoked with too many arguments: .Bl -dash -offset 2n -width 2n -compact .It .Ic \&Fo , .Ic \&MT , .Ic \&PD , .Ic \&RS , .Ic \&UR , .Ic \&ft , or .Ic \&sp with more than one argument .It .Ic \&An with another argument after .Fl split or .Fl nosplit .It .Ic \&RE with more than one argument or with a non-integer argument .It .Ic \&OP or a request of the .Ic \&de family with more than two arguments .It .Ic \&Dt with more than three arguments .It .Ic \&TH with more than five arguments .It .Ic \&Bd , .Ic \&Bk , or .Ic \&Bl with invalid arguments .El The excess arguments are ignored. .El .Ss Unsupported features .Bl -ohang .It Sy "input too large" .Pq mdoc , man Currently, .Nm cannot handle input files larger than its arbitrary size limit of 2^31 bytes (2 Gigabytes). Since useful manuals are always small, this is not a problem in practice. Parsing is aborted as soon as the condition is detected. .It Sy "unsupported control character" .Pq roff An ASCII control character supported by other .Xr roff 7 implementations but not by .Nm was found in an input file. It is replaced by a question mark. .It Sy "unsupported roff request" .Pq roff An input file contains a .Xr roff 7 request supported by GNU troff or Heirloom troff but not by .Nm , and it is likely that this will cause information loss or considerable misformatting. .It Sy "eqn delim option in tbl" .Pq eqn , tbl The options line of a table defines equation delimiters. Any equation source code contained in the table will be printed unformatted. .It Sy "unsupported table layout modifier" .Pq tbl A table layout specification contains an .Sq Cm m modifier. The modifier is discarded. .It Sy "ignoring macro in table" .Pq tbl , mdoc , man A table contains an invocation of an .Xr mdoc 7 or .Xr man 7 macro or of an undefined macro. The macro is ignored, and its arguments are handled as if they were a text line. .El .Sh SEE ALSO .Xr apropos 1 , .Xr man 1 , .Xr eqn 7 , .Xr man 7 , .Xr mandoc_char 7 , .Xr mdoc 7 , .Xr roff 7 , .Xr tbl 7 .Sh HISTORY The .Nm utility first appeared in .Ox 4.8 . The option .Fl I appeared in .Ox 5.2 , and .Fl aCcfhKklMSsw in .Ox 5.7 . .Sh AUTHORS .An -nosplit The .Nm utility was written by .An Kristaps Dzonsons Aq Mt kristaps@bsd.lv and is maintained by .An Ingo Schwarze Aq Mt schwarze@openbsd.org . Index: head/contrib/tnftp/src/ftp_var.h =================================================================== --- head/contrib/tnftp/src/ftp_var.h (revision 337496) +++ head/contrib/tnftp/src/ftp_var.h (revision 337497) @@ -1,355 +1,355 @@ /* $NetBSD: ftp_var.h,v 1.10 2009/05/20 12:53:47 lukem Exp $ */ /* from NetBSD: ftp_var.h,v 1.81 2009/04/12 10:18:52 lukem Exp */ /*- * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Luke Mewburn. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (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) 1985, 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94 */ /* * Copyright (C) 1997 and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * FTP global variables. */ #ifdef SMALL #undef NO_EDITCOMPLETE #define NO_EDITCOMPLETE #undef NO_PROGRESS #define NO_PROGRESS #endif #if 0 /* tnftp */ #include #include #include #include #include #include #endif /* tnftp */ #ifndef NO_EDITCOMPLETE #include #endif /* !NO_EDITCOMPLETE */ #include "extern.h" #include "progressbar.h" /* * Format of command table. */ struct cmd { const char *c_name; /* name of command */ const char *c_help; /* help string */ char c_bell; /* give bell when command completes */ char c_conn; /* must be connected to use command */ char c_proxy; /* proxy server may execute */ #ifndef NO_EDITCOMPLETE const char *c_complete; /* context sensitive completion list */ #endif /* !NO_EDITCOMPLETE */ void (*c_handler)(int, char **); /* function to call */ }; #define MAX_C_NAME 12 /* maximum length of cmd.c_name */ /* * Format of macro table */ struct macel { char mac_name[9]; /* macro name */ char *mac_start; /* start of macro in macbuf */ char *mac_end; /* end of macro in macbuf */ }; /* * Format of option table */ struct option { const char *name; char *value; }; /* * Indices to features[]; an array containing status of remote server * features; -1 not known (FEAT failed), 0 absent, 1 present. */ enum { FEAT_FEAT = 0, /* FEAT, OPTS */ FEAT_MDTM, /* MDTM */ FEAT_MLST, /* MLSD, MLST */ FEAT_REST_STREAM, /* RESTart STREAM */ FEAT_SIZE, /* SIZE */ FEAT_TVFS, /* TVFS (not used) */ FEAT_max }; /* * Global defines */ #define FTPBUFLEN MAXPATHLEN + 200 #define MAX_IN_PORT_T 0xffffU #define HASHBYTES 1024 /* default mark for `hash' command */ #define DEFAULTINCR 1024 /* default increment for `rate' command */ #define FTP_PORT 21 /* default if ! getservbyname("ftp/tcp") */ #define HTTP_PORT 80 /* default if ! getservbyname("http/tcp") */ #ifndef GATE_PORT #define GATE_PORT 21 /* default if ! getservbyname("ftpgate/tcp") */ #endif #ifndef GATE_SERVER #define GATE_SERVER "" /* default server */ #endif -#define DEFAULTPAGER "more" /* default pager if $PAGER isn't set */ +#define DEFAULTPAGER "less" /* default pager if $PAGER isn't set */ #define DEFAULTPROMPT "ftp> " /* default prompt if `set prompt' is empty */ #define DEFAULTRPROMPT "" /* default rprompt if `set rprompt' is empty */ #define TMPFILE "ftpXXXXXXXXXX" #ifndef GLOBAL #define GLOBAL extern #endif /* * Options and other state info. */ GLOBAL int trace; /* trace packets exchanged */ GLOBAL int hash; /* print # for each buffer transferred */ GLOBAL int mark; /* number of bytes between hashes */ GLOBAL int sendport; /* use PORT/LPRT cmd for each data connection */ GLOBAL int connected; /* 1 = connected to server, -1 = logged in */ GLOBAL int interactive; /* interactively prompt on m* cmds */ GLOBAL int confirmrest; /* confirm rest of current m* cmd */ GLOBAL int ftp_debug; /* debugging level */ GLOBAL int bell; /* ring bell on cmd completion */ GLOBAL int doglob; /* glob local file names */ GLOBAL int autologin; /* establish user account on connection */ GLOBAL int proxy; /* proxy server connection active */ GLOBAL int proxflag; /* proxy connection exists */ GLOBAL int gatemode; /* use gate-ftp */ GLOBAL const char *gateserver; /* server to use for gate-ftp */ GLOBAL int sunique; /* store files on server with unique name */ GLOBAL int runique; /* store local files with unique name */ GLOBAL int mcase; /* map upper to lower case for mget names */ GLOBAL int ntflag; /* use ntin ntout tables for name translation */ GLOBAL int mapflag; /* use mapin mapout templates on file names */ GLOBAL int preserve; /* preserve modification time on files */ GLOBAL int code; /* return/reply code for ftp command */ GLOBAL int crflag; /* if 1, strip car. rets. on ascii gets */ GLOBAL int passivemode; /* passive mode enabled */ GLOBAL int activefallback; /* fall back to active mode if passive fails */ GLOBAL char *altarg; /* argv[1] with no shell-like preprocessing */ GLOBAL char ntin[17]; /* input translation table */ GLOBAL char ntout[17]; /* output translation table */ GLOBAL char mapin[MAXPATHLEN]; /* input map template */ GLOBAL char mapout[MAXPATHLEN]; /* output map template */ GLOBAL char typename[32]; /* name of file transfer type */ GLOBAL int type; /* requested file transfer type */ GLOBAL int curtype; /* current file transfer type */ GLOBAL char structname[32]; /* name of file transfer structure */ GLOBAL int stru; /* file transfer structure */ GLOBAL char formname[32]; /* name of file transfer format */ GLOBAL int form; /* file transfer format */ GLOBAL char modename[32]; /* name of file transfer mode */ GLOBAL int mode; /* file transfer mode */ GLOBAL char bytename[32]; /* local byte size in ascii */ GLOBAL int bytesize; /* local byte size in binary */ GLOBAL int anonftp; /* automatic anonymous login */ GLOBAL int dirchange; /* remote directory changed by cd command */ GLOBAL int flushcache; /* set HTTP cache flush headers with request */ GLOBAL int rate_get; /* maximum get xfer rate */ GLOBAL int rate_get_incr; /* increment for get xfer rate */ GLOBAL int rate_put; /* maximum put xfer rate */ GLOBAL int rate_put_incr; /* increment for put xfer rate */ GLOBAL int retry_connect; /* seconds between retrying connection */ GLOBAL const char *tmpdir; /* temporary directory */ GLOBAL int epsv4; /* use EPSV/EPRT on IPv4 connections */ GLOBAL int epsv4bad; /* EPSV doesn't work on the current server */ GLOBAL int epsv6; /* use EPSV/EPRT on IPv6 connections */ GLOBAL int epsv6bad; /* EPSV doesn't work on the current server */ GLOBAL int editing; /* command line editing enabled */ GLOBAL int features[FEAT_max]; /* remote FEATures supported */ #ifndef NO_EDITCOMPLETE GLOBAL EditLine *el; /* editline(3) status structure */ GLOBAL History *hist; /* editline(3) history structure */ GLOBAL char *cursor_pos; /* cursor position we're looking for */ GLOBAL size_t cursor_argc; /* location of cursor in margv */ GLOBAL size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */ #endif /* !NO_EDITCOMPLETE */ GLOBAL char *hostname; /* name of host connected to */ GLOBAL int unix_server; /* server is unix, can use binary for ascii */ GLOBAL int unix_proxy; /* proxy is unix, can use binary for ascii */ GLOBAL char localcwd[MAXPATHLEN]; /* local dir */ GLOBAL char remotecwd[MAXPATHLEN]; /* remote dir */ GLOBAL char *username; /* name of user logged in as. (dynamic) */ GLOBAL sa_family_t family; /* address family to use for connections */ GLOBAL const char *ftpport; /* port number to use for FTP connections */ GLOBAL const char *httpport; /* port number to use for HTTP connections */ GLOBAL const char *gateport; /* port number to use for gateftp connections */ GLOBAL struct addrinfo *bindai; /* local address to bind as */ GLOBAL char *outfile; /* filename to output URLs to */ GLOBAL int restartautofetch; /* restart auto-fetch */ GLOBAL char line[FTPBUFLEN]; /* input line buffer */ GLOBAL char *stringbase; /* current scan point in line buffer */ GLOBAL char argbuf[FTPBUFLEN]; /* argument storage buffer */ GLOBAL char *argbase; /* current storage point in arg buffer */ GLOBAL StringList *marg_sl; /* stringlist containing margv */ GLOBAL int margc; /* count of arguments on input line */ #define margv (marg_sl->sl_str) /* args parsed from input line */ GLOBAL int cpend; /* flag: if != 0, then pending server reply */ GLOBAL int mflag; /* flag: if != 0, then active multi command */ GLOBAL int options; /* used during socket creation */ GLOBAL int sndbuf_size; /* socket send buffer size */ GLOBAL int rcvbuf_size; /* socket receive buffer size */ GLOBAL int macnum; /* number of defined macros */ GLOBAL struct macel macros[16]; GLOBAL char macbuf[4096]; GLOBAL char *localhome; /* local home directory */ GLOBAL char *localname; /* local user name */ GLOBAL char netrc[MAXPATHLEN]; /* path to .netrc file */ GLOBAL char reply_string[BUFSIZ]; /* first line of previous reply */ GLOBAL void (*reply_callback)(const char *); /* * function to call for each line in * the server's reply except for the * first (`xxx-') and last (`xxx ') */ GLOBAL volatile sig_atomic_t sigint_raised; GLOBAL FILE *cin; GLOBAL FILE *cout; GLOBAL int data; extern struct cmd cmdtab[]; extern struct option optiontab[]; #define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0')) #define FREEPTR(x) if ((x) != NULL) { free(x); (x) = NULL; } #ifdef BSD4_4 # define HAVE_STRUCT_SOCKADDR_IN_SIN_LEN 1 #endif #ifdef NO_LONG_LONG # define STRTOLL(x,y,z) strtol(x,y,z) #else # define STRTOLL(x,y,z) strtoll(x,y,z) #endif #ifdef NO_DEBUG #define DPRINTF(...) #define DWARN(...) #else #define DPRINTF(...) if (ftp_debug) (void)fprintf(ttyout, __VA_ARGS__) #define DWARN(...) if (ftp_debug) warn(__VA_ARGS__) #endif #define STRorNULL(s) ((s) ? (s) : "") #ifdef NO_USAGE void xusage(void); #define UPRINTF(...) xusage() #else #define UPRINTF(...) (void)fprintf(ttyout, __VA_ARGS__) #endif Index: head/etc/root/dot.cshrc =================================================================== --- head/etc/root/dot.cshrc (revision 337496) +++ head/etc/root/dot.cshrc (revision 337497) @@ -1,43 +1,43 @@ # $FreeBSD$ # # .cshrc - csh resource script, read at beginning of execution by each shell # # see also csh(1), environ(7). # more examples available at /usr/share/examples/csh/ # alias h history 25 alias j jobs -l alias la ls -aF alias lf ls -FA alias ll ls -lAF # A righteous umask umask 22 set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) setenv EDITOR vi -setenv PAGER more +setenv PAGER less setenv BLOCKSIZE K if ($?prompt) then # An interactive shell -- set some stuff up set prompt = "%N@%m:%~ %# " set promptchars = "%#" set filec set history = 1000 set savehist = (1000 merge) set autolist = ambiguous # Use history to aid expansion set autoexpand set autorehash set mail = (/var/mail/$USER) if ( $?tcsh ) then bindkey "^W" backward-delete-word bindkey -k up history-search-backward bindkey -k down history-search-forward endif endif Index: head/etc/root/dot.profile =================================================================== --- head/etc/root/dot.profile (revision 337496) +++ head/etc/root/dot.profile (revision 337497) @@ -1,16 +1,16 @@ # $FreeBSD$ # PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:~/bin export PATH HOME=/root export HOME TERM=${TERM:-xterm} export TERM -PAGER=more +PAGER=less export PAGER # Query terminal size; useful for serial lines. if [ -x /usr/bin/resizewin ] ; then /usr/bin/resizewin -z ; fi # Uncomment to display a random cookie on each login. # if [ -x /usr/bin/fortune ] ; then /usr/bin/fortune -s ; fi Index: head/share/skel/dot.cshrc =================================================================== --- head/share/skel/dot.cshrc (revision 337496) +++ head/share/skel/dot.cshrc (revision 337497) @@ -1,44 +1,44 @@ # $FreeBSD$ # # .cshrc - csh resource script, read at beginning of execution by each shell # # see also csh(1), environ(7). # more examples available at /usr/share/examples/csh/ # alias h history 25 alias j jobs -l alias la ls -aF alias lf ls -FA alias ll ls -lAF # These are normally set through /etc/login.conf. You may override them here # if wanted. # set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) # setenv BLOCKSIZE K # A righteous umask # umask 22 setenv EDITOR vi -setenv PAGER more +setenv PAGER less if ($?prompt) then # An interactive shell -- set some stuff up set prompt = "%N@%m:%~ %# " set promptchars = "%#" set filec set history = 1000 set savehist = (1000 merge) set autolist = ambiguous # Use history to aid expansion set autoexpand set autorehash set mail = (/var/mail/$USER) if ( $?tcsh ) then bindkey "^W" backward-delete-word bindkey -k up history-search-backward bindkey -k down history-search-forward endif endif Index: head/share/skel/dot.mailrc =================================================================== --- head/share/skel/dot.mailrc (revision 337496) +++ head/share/skel/dot.mailrc (revision 337497) @@ -1,17 +1,17 @@ # $FreeBSD$ # # .mailrc - mail resources # # see also mail(1) # set append ask autoprint set indentprefix="> " -set PAGER=more +set PAGER=less set EDITOR=vi set VISUAL=vi set folder=Mail retain bcc cc date from subject to # include your private mail aliases source ~/.mail_aliases Index: head/share/skel/dot.profile =================================================================== --- head/share/skel/dot.profile (revision 337496) +++ head/share/skel/dot.profile (revision 337497) @@ -1,28 +1,28 @@ # $FreeBSD$ # # .profile - Bourne Shell startup script for login shells # # see also sh(1), environ(7). # # These are normally set through /etc/login.conf. You may override them here # if wanted. # PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:$HOME/bin; export PATH # BLOCKSIZE=K; export BLOCKSIZE # Setting TERM is normally done through /etc/ttys. Do only override # if you're sure that you'll never log in via telnet or xterm or a # serial line. # TERM=xterm; export TERM EDITOR=vi; export EDITOR -PAGER=more; export PAGER +PAGER=less; export PAGER # set ENV to a file invoked each time sh is started for interactive use. ENV=$HOME/.shrc; export ENV # Query terminal size; useful for serial lines. if [ -x /usr/bin/resizewin ] ; then /usr/bin/resizewin -z ; fi # Display a random cookie on each login. if [ -x /usr/bin/fortune ] ; then /usr/bin/fortune freebsd-tips ; fi Index: head/tools/tools/nanobsd/pcengines/Files/root/.cshrc =================================================================== --- head/tools/tools/nanobsd/pcengines/Files/root/.cshrc (revision 337496) +++ head/tools/tools/nanobsd/pcengines/Files/root/.cshrc (revision 337497) @@ -1,35 +1,35 @@ # $FreeBSD$ # # .cshrc - csh resource script, read at beginning of execution by each shell # # see also csh(1), environ(7). # alias h history 25 alias j jobs -l alias la ls -a alias lf ls -FA alias ll ls -lA # A righteous umask umask 22 set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin $HOME/bin) setenv EDITOR vi -setenv PAGER more +setenv PAGER less setenv BLOCKSIZE K if ($?prompt) then # An interactive shell -- set some stuff up set prompt = "`/bin/hostname -s`# " set filec set history = 100 set savehist = 100 set mail = (/var/mail/$USER) if ( $?tcsh ) then bindkey "^W" backward-delete-word bindkey -k up history-search-backward bindkey -k down history-search-forward endif endif Index: head/tools/tools/nanobsd/rescue/Files/root/.cshrc =================================================================== --- head/tools/tools/nanobsd/rescue/Files/root/.cshrc (revision 337496) +++ head/tools/tools/nanobsd/rescue/Files/root/.cshrc (revision 337497) @@ -1,41 +1,41 @@ # $FreeBSD$ # #csh .cshrc file alias a alias a h history 25 a j jobs -l a la ls -a a lf ls -FA a ll ls -lA - a lm 'll | more' - a m more + a lm 'll | less' + a m less set path = (/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin /usr/X11R6/bin /usr/local/jdk1.6.0/bin /usr/local/jdk1.5.0/bin $HOME/bin) setenv MANPATH "/usr/share/man:/usr/X11R6/man:/usr/local/man" -setenv PAGER more +setenv PAGER less setenv EDITOR vi setenv BLOCKSIZE K setenv FTP_PASSIVE_MODE YES #setenv JAVA_HOME /usr/local/jdk1.6.0 #setenv JDK_HOME /usr/local/jdk1.6.0 #setenv JAVA_VERSION 1.5+ #setenv JAVA_VERSION 1.4 #setenv LANG de_DE.UTF-8 setenv CVS_RSH ssh if ($?prompt) then # An interactive shell -- set some stuff up set prompt = "`hostname -s`# " set filec set history = 100 set savehist = 100 set mail = (/var/mail/$USER) set autolist set matchbeep=ambiguos set autoexpand set autocorrect set ignoreeof set correct=cmd endif Index: head/usr.bin/mail/cmd1.c =================================================================== --- head/usr.bin/mail/cmd1.c (revision 337496) +++ head/usr.bin/mail/cmd1.c (revision 337497) @@ -1,477 +1,477 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include "rcv.h" #include "extern.h" /* * Mail -- a mail program * * User commands. */ /* * Print the current active headings. * Don't change dot if invoker didn't give an argument. */ static int screen; int headers(void *v) { int *msgvec = v; int n, mesg, flag, size; struct message *mp; size = screensize(); n = msgvec[0]; if (n != 0) screen = (n-1)/size; if (screen < 0) screen = 0; mp = &message[screen * size]; if (mp >= &message[msgCount]) mp = &message[msgCount - size]; if (mp < &message[0]) mp = &message[0]; flag = 0; mesg = mp - &message[0]; if (dot != &message[n-1]) dot = mp; for (; mp < &message[msgCount]; mp++) { mesg++; if (mp->m_flag & MDELETED) continue; if (flag++ >= size) break; printhead(mesg); } if (flag == 0) { printf("No more mail.\n"); return (1); } return (0); } /* * Scroll to the next/previous screen */ int scroll(void *v) { char *arg = v; int s, size; int cur[1]; cur[0] = 0; size = screensize(); s = screen; switch (*arg) { case 0: case '+': s++; if (s * size >= msgCount) { printf("On last screenful of messages\n"); return (0); } screen = s; break; case '-': if (--s < 0) { printf("On first screenful of messages\n"); return (0); } screen = s; break; default: printf("Unrecognized scrolling command \"%s\"\n", arg); return (1); } return (headers(cur)); } /* * Compute screen size. */ int screensize(void) { int s; char *cp; if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0) return (s); return (screenheight - 4); } /* * Print out the headlines for each message * in the passed message list. */ int from(void *v) { int *msgvec = v; int *ip; for (ip = msgvec; *ip != 0; ip++) printhead(*ip); if (--ip >= msgvec) dot = &message[*ip - 1]; return (0); } /* * Print out the header of a specific message. * This is a slight improvement to the standard one. */ void printhead(int mesg) { struct message *mp; char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind; char pbuf[BUFSIZ]; struct headline hl; int subjlen; char *name; mp = &message[mesg-1]; (void)readline(setinput(mp), headline, LINESIZE); if ((subjline = hfield("subject", mp)) == NULL) subjline = hfield("subj", mp); /* * Bletch! */ curind = dot == mp ? '>' : ' '; dispc = ' '; if (mp->m_flag & MSAVED) dispc = '*'; if (mp->m_flag & MPRESERVE) dispc = 'P'; if ((mp->m_flag & (MREAD|MNEW)) == MNEW) dispc = 'N'; if ((mp->m_flag & (MREAD|MNEW)) == 0) dispc = 'U'; if (mp->m_flag & MBOX) dispc = 'M'; parse(headline, &hl, pbuf); sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size); subjlen = screenwidth - 50 - strlen(wcount); name = value("show-rcpt") != NULL ? skin(hfield("to", mp)) : nameof(mp, 0); if (subjline == NULL || subjlen < 0) /* pretty pathetic */ printf("%c%c%3d %-20.20s %16.16s %s\n", curind, dispc, mesg, name, hl.l_date, wcount); else printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n", curind, dispc, mesg, name, hl.l_date, wcount, subjlen, subjline); } /* * Print out the value of dot. */ int pdot(void) { printf("%td\n", dot - &message[0] + 1); return (0); } /* * Print out all the possible commands. */ int pcmdlist(void) { extern const struct cmd cmdtab[]; const struct cmd *cp; int cc; printf("Commands are:\n"); for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { cc += strlen(cp->c_name) + 2; if (cc > 72) { printf("\n"); cc = strlen(cp->c_name) + 2; } if ((cp+1)->c_name != NULL) printf("%s, ", cp->c_name); else printf("%s\n", cp->c_name); } return (0); } /* * Paginate messages, honor ignored fields. */ int more(void *v) { int *msgvec = v; return (type1(msgvec, 1, 1)); } /* * Paginate messages, even printing ignored fields. */ int More(void *v) { int *msgvec = v; return (type1(msgvec, 0, 1)); } /* * Type out messages, honor ignored fields. */ int type(void *v) { int *msgvec = v; return (type1(msgvec, 1, 0)); } /* * Type out messages, even printing ignored fields. */ int Type(void *v) { int *msgvec = v; return (type1(msgvec, 0, 0)); } /* * Type out the messages requested. */ static jmp_buf pipestop; int type1(int *msgvec, int doign, int page) { int nlines, *ip; struct message *mp; char *cp; FILE *obuf; obuf = stdout; if (setjmp(pipestop)) goto close_pipe; if (value("interactive") != NULL && (page || (cp = value("crt")) != NULL)) { nlines = 0; if (!page) { for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) nlines += message[*ip - 1].m_lines; } if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) { cp = value("PAGER"); if (cp == NULL || *cp == '\0') - cp = _PATH_MORE; + cp = _PATH_LESS; obuf = Popen(cp, "w"); if (obuf == NULL) { warnx("%s", cp); obuf = stdout; } else (void)signal(SIGPIPE, brokpipe); } } /* * Send messages to the output. * */ for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); dot = mp; if (value("quiet") == NULL) fprintf(obuf, "Message %d:\n", *ip); (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL); } close_pipe: if (obuf != stdout) { /* * Ignore SIGPIPE so it can't cause a duplicate close. */ (void)signal(SIGPIPE, SIG_IGN); (void)Pclose(obuf); (void)signal(SIGPIPE, SIG_DFL); } return (0); } /* * Respond to a broken pipe signal -- * probably caused by quitting more. */ /*ARGSUSED*/ void brokpipe(int signo __unused) { longjmp(pipestop, 1); } /* * Print the top so many lines of each desired message. * The number of lines is taken from the variable "toplines" * and defaults to 5. */ int top(void *v) { int *msgvec = v; int *ip; struct message *mp; int c, topl, lines, lineb; char *valtop, linebuf[LINESIZE]; FILE *ibuf; topl = 5; valtop = value("toplines"); if (valtop != NULL) { topl = atoi(valtop); if (topl < 0 || topl > 10000) topl = 5; } lineb = 1; for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { mp = &message[*ip - 1]; touch(mp); dot = mp; if (value("quiet") == NULL) printf("Message %d:\n", *ip); ibuf = setinput(mp); c = mp->m_lines; if (!lineb) printf("\n"); for (lines = 0; lines < c && lines <= topl; lines++) { if (readline(ibuf, linebuf, sizeof(linebuf)) < 0) break; puts(linebuf); lineb = strspn(linebuf, " \t") == strlen(linebuf); } } return (0); } /* * Touch all the given messages so that they will * get mboxed. */ int stouch(void *v) { int *msgvec = v; int *ip; for (ip = msgvec; *ip != 0; ip++) { dot = &message[*ip-1]; dot->m_flag |= MTOUCH; dot->m_flag &= ~MPRESERVE; } return (0); } /* * Make sure all passed messages get mboxed. */ int mboxit(void *v) { int *msgvec = v; int *ip; for (ip = msgvec; *ip != 0; ip++) { dot = &message[*ip-1]; dot->m_flag |= MTOUCH|MBOX; dot->m_flag &= ~MPRESERVE; } return (0); } /* * List the folders the user currently has. */ int folders(void) { char dirname[PATHSIZE]; char *cmd; if (getfold(dirname, sizeof(dirname)) < 0) { printf("No value set for \"folder\"\n"); return (1); } if ((cmd = value("LISTER")) == NULL) cmd = "ls"; (void)run_command(cmd, 0, -1, -1, dirname, NULL); return (0); } /* * Update the mail file with any new messages that have * come in since we started reading mail. */ int inc(void *v __unused) { int nmsg, mdot; nmsg = incfile(); if (nmsg == 0) printf("No new mail.\n"); else if (nmsg > 0) { mdot = newfileinfo(msgCount - nmsg); dot = &message[mdot - 1]; } else printf("\"inc\" command failed...\n"); return (0); } Index: head/usr.bin/mail/mail.1 =================================================================== --- head/usr.bin/mail/mail.1 (revision 337496) +++ head/usr.bin/mail/mail.1 (revision 337497) @@ -1,1273 +1,1273 @@ .\" 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. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)mail.1 8.8 (Berkeley) 4/28/95 .\" $FreeBSD$ .\" -.Dd January 5, 2006 +.Dd August 8, 2018 .Dt MAIL 1 .Os .Sh NAME .Nm mail , .Nm Mail , .Nm mailx .Nd send and receive mail .Sh SYNOPSIS .Nm .Op Fl dEiInv .Op Fl s Ar subject .Op Fl c Ar cc-addr .Op Fl b Ar bcc-addr .Op Fl F .Ar to-addr ... .Op Fl Ar sendmail-option ... .Nm .Op Fl dEHiInNv .Op Fl F .Fl f .Op Ar name .Nm .Op Fl dEHiInNv .Op Fl F .Op Fl u Ar user .Nm .Op Fl d .Fl e .Op Fl f Ar name .Sh INTRODUCTION The .Nm utility is an intelligent mail processing system, which has a command syntax reminiscent of .Xr ed 1 with lines replaced by messages. .Pp The following options are available: .Bl -tag -width indent .It Fl v Verbose mode. The details of delivery are displayed on the user's terminal. .It Fl d Debugging mode. See the .Va debug mail option for details. .It Fl e Test for the presence of mail in the (by default, system) mailbox. An exit status of 0 is returned if it has mail; otherwise, an exit status of 1 is returned. .It Fl H Write a header summary only, then exit. .It Fl E Do not send messages with an empty body. This is useful for piping errors from .Xr cron 8 scripts. .It Fl i Ignore tty interrupt signals. This is particularly useful when using .Nm on noisy phone lines. .It Fl I Force .Nm to run in interactive mode even when input is not a terminal. In particular, the .Ql ~ special character when sending mail is only active in interactive mode. .It Fl n Inhibit reading the system-wide .Pa mail.rc files upon startup. .It Fl N Inhibit the initial display of message headers when reading mail or editing a mail folder. .It Fl s Ar subject Specify .Ar subject on command line. (Only the first argument after the .Fl s flag is used as a subject; be careful to quote subjects containing spaces.) .It Fl c Ar cc-addr Send carbon copies to .Ar cc-addr list of users. The .Ar cc-addr argument should be a comma-separated list of names. .It Fl b Ar bcc-addr Send blind carbon copies to .Ar bcc-addr list of users. The .Ar bcc-addr argument should be a comma-separated list of names. .It Fl f Op Ar mbox Read in the contents of your .Pa mbox (or the specified file) for processing; when you .Ic quit , .Nm writes undeleted messages back to this file. .It Fl F Record the message in a file named after the first recipient. The name is the login-name portion of the address found first on the .Dq Li To: line in the mail header. Overrides the .Va record variable, if set. .It Fl u Ar user Is equivalent to: .Pp .Dl "mail -f /var/mail/user" .El .Ss "Startup Actions" At startup time .Nm will execute commands in the system command files .Pa /usr/share/misc/mail.rc , .Pa /usr/local/etc/mail.rc and .Pa /etc/mail.rc in order, unless explicitly told not to by the use of the .Fl n option. Next, the commands in the user's personal command file .Pa ~/.mailrc are executed. The .Nm utility then examines its command line options to determine whether a new message is to be sent, or whether an existing mailbox is to be read. .Ss "Sending Mail" To send a message to one or more people, .Nm can be invoked with arguments which are the names of people to whom the mail will be sent. You are then expected to type in your message, followed by a .Aq Li control-D at the beginning of a line. The section below .Sx "Replying To or Originating Mail" , describes some features of .Nm available to help you compose your letter. .Ss "Reading Mail" In normal usage .Nm is given no arguments and checks your mail out of the post office, then prints out a one line header of each message found. The current message is initially the first message (numbered 1) and can be printed using the .Ic print command (which can be abbreviated .Ic p ) . You can move among the messages much as you move between lines in .Xr ed 1 , with the commands .Ic + and .Ic \- moving backwards and forwards, and simple numbers. .Ss "Disposing of Mail" After examining a message you can .Ic delete .Pq Ic d the message or .Ic reply .Pq Ic r to it. Deletion causes the .Nm program to forget about the message. This is not irreversible; the message can be .Ic undeleted .Pq Ic u by giving its number, or the .Nm session can be aborted by giving the .Ic exit .Pq Ic x command. Deleted messages will, however, usually disappear never to be seen again. .Ss "Specifying Messages" Commands such as .Ic print and .Ic delete can be given a list of message numbers as arguments to apply to a number of messages at once. Thus .Dq Li "delete 1 2" deletes messages 1 and 2, while .Dq Li "delete 1\-5" deletes messages 1 through 5. The special name .Ql * addresses all messages, and .Ql $ addresses the last message; thus the command .Ic top which prints the first few lines of a message could be used in .Dq Li "top *" to print the first few lines of all messages. .Ss "Replying To or Originating Mail" You can use the .Ic reply command to set up a response to a message, sending it back to the person who it was from. Text you then type in, up to an end-of-file, defines the contents of the message. While you are composing a message, .Nm treats lines beginning with the character .Ql ~ specially. For instance, typing .Ic ~m (alone on a line) will place a copy of the current message into the response right shifting it by a tabstop (see .Va indentprefix variable, below). Other escapes will set up subject fields, add and delete recipients to the message and allow you to escape to an editor to revise the message or to a shell to run some commands. (These options are given in the summary below.) .Ss "Ending a Mail Processing Session" You can end a .Nm session with the .Ic quit .Pq Ic q command. Messages which have been examined go to your .Pa mbox file unless they have been deleted in which case they are discarded. Unexamined messages go back to the post office. (See the .Fl f option above). .Ss "Personal and System Wide Distribution Lists" It is also possible to create a personal distribution lists so that, for instance, you can send mail to .Dq Li cohorts and have it go to a group of people. Such lists can be defined by placing a line like .Pp .Dl "alias cohorts bill ozalp jkf mark kridle@ucbcory" .Pp in the file .Pa .mailrc in your home directory. The current list of such aliases can be displayed with the .Ic alias command in .Nm . System wide distribution lists can be created by editing .Pa /etc/mail/aliases , see .Xr aliases 5 and .Xr sendmail 8 ; these are kept in a different syntax. In mail you send, personal aliases will be expanded in mail sent to others so that they will be able to .Ic reply to the recipients. System wide aliases are not expanded when the mail is sent, but any reply returned to the machine will have the system wide alias expanded as all mail goes through .Xr sendmail 8 . .Ss "Network Mail (ARPA, UUCP, Berknet)" .Pp The .Nm utility has a number of options which can be set in the .Pa .mailrc file to alter its behavior; thus .Dq Li "set askcc" enables the .Va askcc feature. (These options are summarized below.) .Sh SUMMARY (Adapted from the .%T "Mail Reference Manual" . ) .Pp Each command is typed on a line by itself, and may take arguments following the command word. The command need not be typed in its entirety \(em the first command which matches the typed prefix is used. For commands which take message lists as arguments, if no message list is given, then the next message forward which satisfies the command's requirements is used. If there are no messages forward of the current message, the search proceeds backwards, and if there are no good messages at all, .Nm types .Dq Li "No applicable messages" and aborts the command. .Bl -tag -width indent .It Ic \- Print out the preceding message. If given a numeric argument .Ar n , goes to the .Ar n Ns 'th previous message and prints it. .It Ic # ignore the remainder of the line as a comment. .It Ic \&? Prints a brief summary of commands. .It Ic \&! Executes the shell (see .Xr sh 1 and .Xr csh 1 ) command which follows. .It Ic Print .Pq Ic P Like .Ic print but also prints out ignored header fields. See also .Ic print , ignore and .Ic retain . .It Ic Reply .Pq Ic R Reply to originator. Does not reply to other recipients of the original message. .It Ic Type .Pq Ic T Identical to the .Ic Print command. .It Ic alias .Pq Ic a With no arguments, prints out all currently-defined aliases. With one argument, prints out that alias. With more than one argument, creates a new alias or changes an old one. .It Ic alternates .Pq Ic alt The .Ic alternates command is useful if you have accounts on several machines. It can be used to inform .Nm that the listed addresses are really you. When you .Ic reply to messages, .Nm will not send a copy of the message to any of the addresses listed on the .Ic alternates list. If the .Ic alternates command is given with no argument, the current set of alternative names is displayed. .It Ic chdir .Pq Ic c Changes the user's working directory to that specified, if given. If no directory is given, then changes to the user's login directory. .It Ic copy .Pq Ic co The .Ic copy command does the same thing that .Ic save does, except that it does not mark the messages it is used on for deletion when you .Ic quit . .It Ic delete .Pq Ic d Takes a list of messages as argument and marks them all as deleted. Deleted messages will not be saved in .Pa mbox , nor will they be available for most other commands. .It Ic dp (also .Ic dt ) Deletes the current message and prints the next message. If there is no next message, .Nm says .Dq Li "at EOF" . .It Ic edit .Pq Ic e Takes a list of messages and points the text editor at each one in turn. On return from the editor, the message is read back in. .It Ic exit .Ic ( ex or .Ic x ) Effects an immediate return to the shell without modifying the user's system mailbox, his .Pa mbox file, or his edit file in .Fl f . .It Ic file .Pq Ic fi The same as .Ic folder . .It Ic folders List the names of the folders in your folder directory. .It Ic folder .Pq Ic fo The .Ic folder command switches to a new mail file or folder. With no arguments, it tells you which file you are currently reading. If you give it an argument, it will write out changes (such as deletions) you have made in the current file and read in the new file. Some special conventions are recognized for the name. .Ql # means the previous file, .Ql % means your system mailbox, .Dq Li % Ns Ar user means user's system mailbox, .Ql & means your .Pa mbox file, and .Dq Li + Ns Ar folder means a file in your folder directory. .It Ic from .Pq Ic f Takes a list of messages and prints their message headers. .It Ic headers .Pq Ic h Lists the current range of headers, which is an 18-message group. If a .Ql + argument is given, then the next 18-message group is printed, and if a .Ql \- argument is given, the previous 18-message group is printed. .It Ic help A synonym for .Ic \&? . .It Ic hold .Ic ( ho , also .Ic preserve ) Takes a message list and marks each message therein to be saved in the user's system mailbox instead of in .Pa mbox . Does not override the .Ic delete command. .It Ic ignore Add the list of header fields named to the .Ar ignored list . Header fields in the ignore list are not printed on your terminal when you print a message. This command is very handy for suppression of certain machine-generated header fields. The .Ic Type and .Ic Print commands can be used to print a message in its entirety, including ignored fields. If .Ic ignore is executed with no arguments, it lists the current set of ignored fields. .It Ic inc Incorporate any new messages that have arrived while mail is being read. The new messages are added to the end of the message list, and the current message is reset to be the first new mail message. This does not renumber the existing message list, nor does it cause any changes made so far to be saved. .It Ic mail .Pq Ic m Takes as argument login names and distribution group names and sends mail to those people. .It Ic mbox Indicate that a list of messages be sent to .Pa mbox in your home directory when you quit. This is the default action for messages if you do .Em not have the .Ic hold option set. .It Ic more .Pq Ic mo Takes a list of messages and invokes the pager on that list. .It Ic next .Ic ( n , like .Ic + or .Tn CR ) Goes to the next message in sequence and types it. With an argument list, types the next matching message. .It Ic preserve .Pq Ic pre A synonym for .Ic hold . .It Ic print .Pq Ic p Takes a message list and types out each message on the user's terminal. .It Ic quit .Pq Ic q Terminates the session, saving all undeleted, unsaved messages in the user's .Pa mbox file in his login directory, preserving all messages marked with .Ic hold or .Ic preserve or never referenced in his system mailbox, and removing all other messages from his system mailbox. If new mail has arrived during the session, the message .Dq Li "You have new mail" is given. If given while editing a mailbox file with the .Fl f flag, then the edit file is rewritten. A return to the shell is effected, unless the rewrite of edit file fails, in which case the user can escape with the .Ic exit command. .It Ic reply .Pq Ic r Takes a message list and sends mail to the sender and all recipients of the specified message. The default message must not be deleted. .It Ic respond A synonym for .Ic reply . .It Ic retain Add the list of header fields named to the .Em "retained list" . Only the header fields in the retained list are shown on your terminal when you print a message. All other header fields are suppressed. The .Ic type and .Ic print commands can be used to print a message in its entirety. If .Ic retain is executed with no arguments, it lists the current set of retained fields. .It Ic save .Pq Ic s Takes a message list and a filename and appends each message in turn to the end of the file. The filename in quotes, followed by the line count and character count is echoed on the user's terminal. .It Ic set .Pq Ic se With no arguments, prints all variable values. Otherwise, sets option. Arguments are of the form .Ar option Ns Li = Ns Ar value (no space before or after .Ql = ) or .Ar option . Quotation marks may be placed around any part of the assignment statement to quote blanks or tabs, i.e.\& .Dq Li "set indentprefix=\*q->\*q" .It Ic saveignore .Ic Saveignore is to .Ic save what .Ic ignore is to .Ic print and .Ic type . Header fields thus marked are filtered out when saving a message by .Ic save or when automatically saving to .Pa mbox . .It Ic saveretain .Ic Saveretain is to .Ic save what .Ic retain is to .Ic print and .Ic type . Header fields thus marked are the only ones saved with a message when saving by .Ic save or when automatically saving to .Pa mbox . .Ic Saveretain overrides .Ic saveignore . .It Ic shell .Pq Ic sh Invokes an interactive version of the shell. .It Ic size Takes a message list and prints out the size in characters of each message. .It Ic source The .Ic source command reads commands from a file. .It Ic top Takes a message list and prints the top few lines of each. The number of lines printed is controlled by the variable .Va toplines and defaults to 5. .It Ic type .Pq Ic t A synonym for .Ic print . .It Ic unalias Takes a list of names defined by .Ic alias commands and discards the remembered groups of users. The group names no longer have any significance. .It Ic undelete .Pq Ic u Takes a message list and marks each message as .Em not being deleted. .It Ic unread .Pq Ic U Takes a message list and marks each message as .Em not having been read. .It Ic unset Takes a list of option names and discards their remembered values; the inverse of .Ic set . .It Ic visual .Pq Ic v Takes a message list and invokes the display editor on each message. .It Ic write .Pq Ic w Similar to .Ic save , except that .Em only the message body .Em ( without the header) is saved. Extremely useful for such tasks as sending and receiving source program text over the message system. .It Ic xit .Pq Ic x A synonym for .Ic exit . .It Ic z The .Nm utility presents message headers in windowfuls as described under the .Ic headers command. You can move .Nm Ns 's attention forward to the next window with the .Ic z command. Also, you can move to the previous window by using .Ic z\- . .El .Ss Tilde/Escapes Here is a summary of the tilde escapes, which are used when composing messages to perform special functions. Tilde escapes are only recognized at the beginning of lines. The name .Dq "tilde escape" is somewhat of a misnomer since the actual escape character can be set by the option .Va escape . .Bl -tag -width indent .It Ic ~a Inserts the autograph string from the sign= option into the message. .It Ic ~A Inserts the autograph string from the Sign= option into the message. .It Ic ~b Ar name ... Add the given names to the list of carbon copy recipients but do not make the names visible in the Cc: line .Dq ( blind carbon copy). .It Ic ~c Ar name ... Add the given names to the list of carbon copy recipients. .It Ic ~d Read the file .Pa dead.letter from your home directory into the message. .It Ic ~e Invoke the text editor on the message collected so far. After the editing session is finished, you may continue appending text to the message. .It Ic ~f Ar messages Read the named messages into the message being sent. If no messages are specified, read in the current message. Message headers currently being ignored (by the .Ic ignore or .Ic retain command) are not included. .It Ic ~F Ar messages Identical to .Ic ~f , except all message headers are included. .It Ic ~h Edit the message header fields by typing each one in turn and allowing the user to append text to the end or modify the field by using the current terminal erase and kill characters. .It Ic ~i Ar string Inserts the value of the named option into the text of the message. .It Ic ~m Ar messages Read the named messages into the message being sent, indented by a tab or by the value of .Va indentprefix . If no messages are specified, read the current message. Message headers currently being ignored (by the .Ic ignore or .Ic retain command) are not included. .It Ic ~M Ar messages Identical to .Ic ~m , except all message headers are included. .It Ic ~p Print out the message collected so far, prefaced by the message header fields. .It Ic ~q Abort the message being sent, copying the message to .Pa dead.letter in your home directory if .Va save is set. .It Ic ~r Ar filename , Ic ~r Li \&! Ns Ar command .It Ic ~< Ar filename , Ic ~< Li \&! Ns Ar command Read the named file into the message. If the argument begins with a .Ql \&! , the rest of the string is taken as an arbitrary system command and is executed, with the standard output inserted into the message. .It Ic ~R Ar string Use .Ar string as the Reply-To field. .It Ic ~s Ar string Cause the named string to become the current subject field. .It Ic ~t Ar name ... Add the given names to the direct recipient list. .It Ic ~v Invoke an alternative editor (defined by the .Ev VISUAL environment variable) on the message collected so far. Usually, the alternative editor will be a screen editor. After you quit the editor, you may resume appending text to the end of your message. .It Ic ~w Ar filename Write the message onto the named file. .It Ic ~x Exits as with .Ic ~q , except the message is not saved in .Pa dead.letter . .It Ic ~! Ar command Execute the indicated shell command, then return to the message. .It Ic ~| Ar command , Ic ~^ Ar command Pipe the message through the command as a filter. If the command gives no output or terminates abnormally, retain the original text of the message. The command .Xr fmt 1 is often used as .Ar command to rejustify the message. .It Ic ~: Ar mail-command , Ic ~_ Ar mail-command Execute the given .Nm command. Not all commands, however, are allowed. .It Ic ~. Simulate end-of-file on input. .It Ic ~? Print a summary of the available command escapes. .It Ic ~~ Ar string Insert the string of text in the message prefaced by a single .Ql ~ . If you have changed the escape character, then you should double that character in order to send it. .El .Ss "Mail Options" Options can be set with the .Ic set command and can be disabled with the .Ic unset or .Ic set Cm no Ns Ar name commands. Options may be either binary, in which case it is only significant to see whether they are set or not; or string, in which case the actual value is of interest. If an option is not set, .Nm will look for an environment variable of the same name. The available options include the following: .Bl -tag -width indent .It Va append Causes messages saved in .Pa mbox to be appended to the end rather than prepended. This should always be set (preferably in one of the system-wide .Pa mail.rc files). Default is .Va noappend . .It Va ask , asksub Causes .Nm to prompt you for the subject of each message you send. If you respond with simply a newline, no subject field will be sent. Default is .Va asksub . .It Va askbcc Causes you to be prompted for additional blind carbon copy recipients at the end of each message. Responding with a newline indicates your satisfaction with the current list. Default is .Va noaskbcc . .It Va askcc Causes you to be prompted for additional carbon copy recipients at the end of each message. Responding with a newline indicates your satisfaction with the current list. Default is .Va noaskcc . .It Va autoinc Causes new mail to be automatically incorporated when it arrives. Setting this is similar to issuing the .Ic inc command at each prompt, except that the current message is not reset when new mail arrives. Default is .Va noautoinc . .It Va autoprint Causes the .Ic delete command to behave like .Ic dp ; thus, after deleting a message, the next one will be typed automatically. Default is .Va noautoprint . .It Va crt The valued option .Va crt is used as a threshold to determine how long a message must be before .Ev PAGER is used to read it. If .Va crt is set without a value, then the height of the terminal screen stored in the system is used to compute the threshold (see .Xr stty 1 ) . Default is .Va nocrt . .It Va debug Setting the binary option .Va debug is the same as specifying .Fl d on the command line and causes .Nm to output all sorts of information useful for debugging .Nm . In case .Nm is invoked in this mode to send mail, all preparations will be performed and reported about, but the mail will not be actually sent. Default is .Va nodebug . .It Va dot The binary option .Va dot causes .Nm to interpret a period alone on a line as the terminator of a message you are sending. Default is .Va nodot . .It Va escape If defined, the first character of this option gives the character to use in place of .Ql ~ to denote escapes. .It Va flipr Reverses the sense of .Ic reply and .Ic Reply commands. Default is .Va noflipr . .It Va folder The name of the directory to use for storing folders of messages. If this name begins with a .Ql / , .Nm considers it to be an absolute pathname; otherwise, the folder directory is found relative to your home directory. .It Va header If defined, initially display message headers when reading mail or editing a mail folder. Default is .Va header . This option can be disabled by giving the .Fl N flag on the command line. .It Va hold This option is used to hold messages in the system mailbox by default. Default is .Va nohold . .It Va ignore Causes interrupt signals from your terminal to be ignored and echoed as .Li @ Ns 's. Default is .Va noignore . .It Va ignoreeof An option related to .Va dot is .Va ignoreeof which makes .Nm refuse to accept a .Aq Li control-D as the end of a message. .Ar Ignoreeof also applies to .Nm command mode. Default is .Va noignoreeof . .It Va indentprefix String used by the .Ic ~m tilde escape for indenting messages, in place of the normal tab character .Pq Li ^I . Be sure to quote the value if it contains spaces or tabs. .It Va metoo Usually, when a group is expanded that contains the sender, the sender is removed from the expansion. Setting this option causes the sender to be included in the group. Default is .Va nometoo . .It Va quiet Suppresses the printing of the version when first invoked. Default is .Va noquiet . .It Va record If defined, gives the pathname of the file used to record all outgoing mail. If not defined, outgoing mail is not saved. Default is .Va norecord . .It Va Replyall Reverses the sense of .Ic reply and .Ic Reply commands. Default is .Va noReplyall . .It Va save If this option is set, and you abort a message with two .Tn RUBOUT (erase or delete), .Nm will copy the partial letter to the file .Pa dead.letter in your home directory. Default is .Va save . .It Va searchheaders If this option is set, then a message-list specifier in the form .Dq Li / Ns Ar x Ns : Ns Ar y will expand to all messages containing the substring .Ar y in the header field .Ar x . The string search is case insensitive. If .Ar x is omitted, it will default to the .Dq Li Subject header field. The form .Dq Li /to: Ns Ar y is a special case, and will expand to all messages containing the substring .Ar y in the .Dq Li To , .Dq Li Cc or .Dq Li Bcc header fields. The check for .Qq Li "to" is case sensitive, so that .Dq Li /To: Ns Ar y can be used to limit the search for .Ar y to just the .Dq Li To: field. Default is .Va nosearchheaders . .It Va toplines If defined, gives the number of lines of a message to be printed out with the .Ic top command; normally, the first five lines are printed. .It Va verbose Setting the option .Va verbose is the same as using the .Fl v flag on the command line. When .Nm runs in verbose mode, the actual delivery of messages is displayed on the user's terminal. Default is .Va noverbose . .El .Sh ENVIRONMENT .Bl -tag -width ".Ev REPLYTO" .It Ev DEAD Pathname of the file to save partial messages to in case of interrupts or delivery errors. Default is .Pa ~/dead.letter . .It Ev EDITOR Pathname of the text editor to use in the .Ic edit command and .Ic ~e escape. If not defined, then a default editor is used. .It Ev HOME Pathname of the user's home directory. .It Ev LISTER Pathname of the directory lister to use in the .Ic folders command. Default is .Pa /bin/ls . .It Ev MAIL Location of the user's mailbox. Default is .Pa /var/mail . .It Ev MAILRC Pathname of file containing initial .Nm commands. Default is .Pa ~/.mailrc . .It Ev MBOX The name of the mailbox file. It can be the name of a folder. The default is .Pa mbox in the user's home directory. .It Ev PAGER Pathname of the program to use in the .Ic more command or when .Va crt variable is set. The default paginator -.Xr more 1 +.Xr less 1 is used if this option is not defined. .It Ev REPLYTO If set, will be used to initialize the Reply-To field for outgoing messages. .It Ev SHELL Pathname of the shell to use in the .Ic \&! command and the .Ic ~! escape. A default shell is used if this option is not defined. .It Ev TMPDIR Pathname of the directory used for creating temporary files. .It Ev VISUAL Pathname of the text editor to use in the .Ic visual command and .Ic ~v escape. .It Ev USER Login name of the user executing mail. .El .Sh FILES .Bl -tag -width ".Pa /usr/share/misc/mail.*help" -compact .It Pa /var/mail/* Post office. .It Pa ~/mbox User's old mail. .It Pa ~/.mailrc File giving initial .Nm commands. This can be overridden by setting the .Ev MAILRC environment variable. .It Pa /tmp/R* Temporary files. .It Pa /usr/share/misc/mail.*help Help files. .Pp .It Pa /usr/share/misc/mail.rc .It Pa /usr/local/etc/mail.rc .It Pa /etc/mail.rc System-wide initialization files. Each file will be sourced, in order, if it exists. .El .Sh SEE ALSO .Xr fmt 1 , .Xr newaliases 1 , .Xr vacation 1 , .Xr aliases 5 , .Xr sendmail 8 .Sh HISTORY A .Nm command appeared in .At v1 . This man page is derived from .%T "The Mail Reference Manual" originally written by .An Kurt Shoens . .Sh BUGS There are some flags that are not documented here. Most are not useful to the general user. .Pp Usually, .Nm is just a link to .Nm Mail and .Nm mailx , which can be confusing. .Pp The name of the .Ic alternates list is incorrect English (it should be .Dq alternatives ) , but is retained for compatibility. Index: head/usr.bin/mail/pathnames.h =================================================================== --- head/usr.bin/mail/pathnames.h (revision 337496) +++ head/usr.bin/mail/pathnames.h (revision 337497) @@ -1,40 +1,40 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (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 * * $FreeBSD$ */ #define _PATH_EX "/usr/bin/ex" #define _PATH_HELP "/usr/share/misc/mail.help" #define _PATH_TILDE "/usr/share/misc/mail.tildehelp" #define _PATH_MASTER_RC "/usr/share/misc/mail.rc:/usr/local/etc/mail.rc:/etc/mail.rc" -#define _PATH_MORE "/usr/bin/more" +#define _PATH_LESS "/usr/bin/less" Index: head/usr.bin/man/man.1 =================================================================== --- head/usr.bin/man/man.1 (revision 337496) +++ head/usr.bin/man/man.1 (revision 337497) @@ -1,375 +1,375 @@ .\"- .\" Copyright (c) 2010 Gordon Tetlow .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must 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. .\" .\" $FreeBSD$ .\" -.Dd April 25, 2018 +.Dd August 8, 2018 .Dt MAN 1 .Os .Sh NAME .Nm man .Nd display online manual documentation pages .Sh SYNOPSIS .Nm .Op Fl adho .Op Fl t | w .Op Fl M Ar manpath .Op Fl P Ar pager .Op Fl S Ar mansect .Op Fl m Ar arch Ns Op : Ns Ar machine .Op Fl p Op Ar eprtv .Op Ar mansect .Ar page ... .Nm .Fl f .Ar keyword ... .Nm .Fl k .Ar keyword ... .Sh DESCRIPTION The .Nm utility finds and displays online manual documentation pages. If .Ar mansect is provided, .Nm restricts the search to the specific section of the manual. .Pp The sections of the manual are: .Bl -enum -offset indent -compact .It .Fx General Commands Manual .It .Fx System Calls Manual .It .Fx Library Functions Manual .It .Fx Kernel Interfaces Manual .It .Fx File Formats Manual .It .Fx Games Manual .It .Fx Miscellaneous Information Manual .It .Fx System Manager's Manual .It .Fx Kernel Developer's Manual .El .Pp Options that .Nm understands: .Bl -tag -width indent .It Fl M Ar manpath Forces a specific colon separated manual path instead of the default search path. See .Xr manpath 1 . Overrides the .Ev MANPATH environment variable. .It Fl P Ar pager Use specified pager. Defaults to .Dq Li "less -sR" if color support is enabled, or -.Dq Li "more -s" . +.Dq Li "less -s" . Overrides the .Ev MANPAGER environment variable, which in turn overrides the .Ev PAGER environment variable. .It Fl S Ar mansect Restricts manual sections searched to the specified colon delimited list. Defaults to .Dq Li 1:8:2:3:n:4:5:6:7:9:l . Overrides the .Ev MANSECT environment variable. .It Fl a Display all manual pages instead of just the first found for each .Ar page argument. .It Fl d Print extra debugging information. Repeat for increased verbosity. Does not display the manual page. .It Fl f Emulate .Xr whatis 1 . .It Fl h Display short help message and exit. .It Fl k Emulate .Xr apropos 1 . .It Fl m Ar arch Ns Op : Ns Ar machine Override the default architecture and machine settings allowing lookup of other platform specific manual pages. See .Sx IMPLEMENTATION NOTES for how this option changes the default behavior. Overrides the .Ev MACHINE_ARCH and .Ev MACHINE environment variables. .It Fl o Force use of non-localized manual pages. See .Sx IMPLEMENTATION NOTES for how locale specific searches work. Overrides the .Ev LC_ALL , LC_CTYPE , and .Ev LANG environment variables. .It Fl p Op Cm eprtv Use the list of given preprocessors before running .Xr nroff 1 or .Xr troff 1 . Valid preprocessors arguments: .Pp .Bl -tag -width indent -compact .It Cm e .Xr eqn 1 .It Cm p .Xr pic 1 .It Cm r .Xr refer 1 .It Cm t .Xr tbl 1 .It Cm v .Xr vgrind 1 .El .Pp Overrides the .Ev MANROFFSEQ environment variable. .It Fl t Send manual page source through .Xr troff 1 allowing transformation of the manual pages to other formats. .It Fl w Display the location of the manual page instead of the contents of the manual page. .El .Sh IMPLEMENTATION NOTES .Ss Locale Specific Searches The .Nm utility supports manual pages in different locales. The search behavior is dictated by the first of three environment variables with a nonempty string: .Ev LC_ALL , LC_CTYPE , or .Ev LANG . If set, .Nm will search for locale specific manual pages using the following logic: .Pp .Bl -item -offset indent -compact .It .Va lang Ns _ Ns Va country Ns . Ns Va charset .It .Va lang Ns . Ns Va charset .It .Li en Ns . Ns Va charset .El .Pp For example, if .Ev LC_ALL is set to .Dq Li ja_JP.eucJP , .Nm will search the following paths when considering section 1 manual pages in .Pa /usr/share/man : .Pp .Bl -item -offset indent -compact .It .Pa /usr/share/man/ja_JP.eucJP/man1 .It .Pa /usr/share/man/ja.eucJP/man1 .It .Pa /usr/share/man/en.eucJP/man1 .It .Pa /usr/share/man/man1 .El .Ss Platform Specific Searches The .Nm utility supports platform specific manual pages. The search behavior is dictated by the .Fl m option or the .Ev MACHINE_ARCH and .Ev MACHINE environment variables. For example, if .Ev MACHINE_ARCH is set to .Dq Li aarch64 and .Ev MACHINE is set to .Dq Li arm64 , .Nm will search the following paths when considering section 4 manual pages in .Pa /usr/share/man : .Pp .Bl -item -offset indent -compact .It .Pa /usr/share/man/man4/aarch64 .It .Pa /usr/share/man/man4/arm64 .It .Pa /usr/share/man/man4 .El .Ss Displaying Specific Manual Files The .Nm utility also supports displaying a specific manual page if passed a path to the file as long as it contains a .Ql / character. .Sh ENVIRONMENT The following environment variables affect the execution of .Nm : .Bl -tag -width ".Ev MANROFFSEQ" .It Ev LC_ALL , LC_CTYPE , LANG Used to find locale specific manual pages. Valid values can be found by running the .Xr locale 1 command. See .Sx IMPLEMENTATION NOTES for details. Influenced by the .Fl o option. .It Ev MACHINE_ARCH , MACHINE Used to find platform specific manual pages. If unset, the output of .Dq Li "sysctl hw.machine_arch" and .Dq Li "sysctl hw.machine" is used respectively. See .Sx IMPLEMENTATION NOTES for details. Corresponds to the .Fl m option. .It Ev MANPATH The standard search path used by .Xr man 1 may be changed by specifying a path in the .Ev MANPATH environment variable. Invalid paths, or paths without manual databases, are ignored. Overridden by .Fl M . If .Ev MANPATH begins with a colon, it is appended to the default list; if it ends with a colon, it is prepended to the default list; or if it contains two adjacent colons, the standard search path is inserted between the colons. If none of these conditions are met, it overrides the standard search path. .It Ev MANROFFSEQ Used to determine the preprocessors for the manual source before running .Xr nroff 1 or .Xr troff 1 . If unset, defaults to .Xr tbl 1 . Corresponds to the .Fl p option. .It Ev MANSECT Restricts manual sections searched to the specified colon delimited list. Corresponds to the .Fl S option. .It Ev MANWIDTH If set to a numeric value, used as the width manpages should be displayed. Otherwise, if set to a special value .Dq Li tty , and output is to a terminal, the pages may be displayed over the whole width of the screen. .It Ev MANCOLOR If set, enables color support. .It Ev MANPAGER Program used to display files. .Pp If unset, and color support is enabled, .Dq Li "less -sR" is used. .Pp If unset, and color support is disabled, then .Ev PAGER is used. If that has no value either, -.Dq Li "more -s" +.Dq Li "less -s" is used. .El .Sh FILES .Bl -tag -width indent -compact .It Pa /etc/man.conf System configuration file. .It Pa /usr/local/etc/man.d/*.conf Local configuration files. .El .Sh EXIT STATUS .Ex -std .Sh SEE ALSO .Xr apropos 1 , .Xr intro 1 , .Xr mandoc 1 , .Xr manpath 1 , .Xr whatis 1 , .Xr intro 2 , .Xr intro 3 , .Xr intro 4 , .Xr intro 5 , .Xr man.conf 5 , .Xr intro 6 , .Xr intro 7 , .Xr mdoc 7 , .Xr intro 8 , .Xr intro 9 Index: head/usr.bin/man/man.sh =================================================================== --- head/usr.bin/man/man.sh (revision 337496) +++ head/usr.bin/man/man.sh (revision 337497) @@ -1,1024 +1,1024 @@ #! /bin/sh # # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright (c) 2010 Gordon Tetlow # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must 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. # # $FreeBSD$ # Usage: add_to_manpath path # Adds a variable to manpath while ensuring we don't have duplicates. # Returns true if we were able to add something. False otherwise. add_to_manpath() { case "$manpath" in *:$1) decho " Skipping duplicate manpath entry $1" 2 ;; $1:*) decho " Skipping duplicate manpath entry $1" 2 ;; *:$1:*) decho " Skipping duplicate manpath entry $1" 2 ;; *) if [ -d "$1" ]; then decho " Adding $1 to manpath" manpath="$manpath:$1" return 0 fi ;; esac return 1 } # Usage: build_manlocales # Builds a correct MANLOCALES variable. build_manlocales() { # If the user has set manlocales, who are we to argue. if [ -n "$MANLOCALES" ]; then return fi parse_configs # Trim leading colon MANLOCALES=${manlocales#:} decho "Available manual locales: $MANLOCALES" } # Usage: build_manpath # Builds a correct MANPATH variable. build_manpath() { local IFS # If the user has set a manpath, who are we to argue. if [ -n "$MANPATH" ]; then case "$MANPATH" in *:) PREPEND_MANPATH=${MANPATH} ;; :*) APPEND_MANPATH=${MANPATH} ;; *::*) PREPEND_MANPATH=${MANPATH%%::*} APPEND_MANPATH=${MANPATH#*::} ;; *) return ;; esac fi if [ -n "$PREPEND_MANPATH" ]; then IFS=: for path in $PREPEND_MANPATH; do add_to_manpath "$path" done unset IFS fi search_path decho "Adding default manpath entries" IFS=: for path in $man_default_path; do add_to_manpath "$path" done unset IFS parse_configs if [ -n "$APPEND_MANPATH" ]; then IFS=: for path in $APPEND_MANPATH; do add_to_manpath "$path" done unset IFS fi # Trim leading colon MANPATH=${manpath#:} decho "Using manual path: $MANPATH" } # Usage: check_cat catglob # Checks to see if a cat glob is available. check_cat() { if exists "$1"; then use_cat=yes catpage=$found setup_cattool $catpage decho " Found catpage $catpage" return 0 else return 1 fi } # Usage: check_man manglob catglob # Given 2 globs, figures out if the manglob is available, if so, check to # see if the catglob is also available and up to date. check_man() { if exists "$1"; then # We have a match, check for a cat page manpage=$found setup_cattool $manpage decho " Found manpage $manpage" if [ -n "${use_width}" ]; then # non-standard width unset use_cat decho " Skipping catpage: non-standard page width" elif exists "$2" && is_newer $found $manpage; then # cat page found and is newer, use that use_cat=yes catpage=$found setup_cattool $catpage decho " Using catpage $catpage" else # no cat page or is older unset use_cat decho " Skipping catpage: not found or old" fi return 0 fi return 1 } # Usage: decho "string" [debuglevel] # Echoes to stderr string prefaced with -- if high enough debuglevel. decho() { if [ $debug -ge ${2:-1} ]; then echo "-- $1" >&2 fi } # Usage: exists glob # Returns true if glob resolves to a real file. exists() { local IFS # Don't accidentally inherit callers IFS (breaks perl manpages) unset IFS # Use some globbing tricks in the shell to determine if a file # exists or not. set +f set -- "$1" $1 set -f if [ "$1" != "$2" -a -r "$2" ]; then found="$2" return 0 fi return 1 } # Usage: find_file path section subdir pagename # Returns: true if something is matched and found. # Search the given path/section combo for a given page. find_file() { local manroot catroot mann man0 catn cat0 manroot="$1/man$2" catroot="$1/cat$2" if [ -n "$3" ]; then manroot="$manroot/$3" catroot="$catroot/$3" fi if [ ! -d "$manroot" -a ! -d "$catroot" ]; then return 1 fi decho " Searching directory $manroot" 2 mann="$manroot/$4.$2*" man0="$manroot/$4.0*" catn="$catroot/$4.$2*" cat0="$catroot/$4.0*" # This is the behavior as seen by the original man utility. # Let's not change that which doesn't seem broken. if check_man "$mann" "$catn"; then return 0 elif check_man "$man0" "$cat0"; then return 0 elif check_cat "$catn"; then return 0 elif check_cat "$cat0"; then return 0 fi return 1 } # Usage: is_newer file1 file2 # Returns true if file1 is newer than file2 as calculated by mtime. is_newer() { if ! [ "$1" -ot "$2" ]; then decho " mtime: $1 not older than $2" 3 return 0 else decho " mtime: $1 older than $2" 3 return 1 fi } # Usage: manpath_parse_args "$@" # Parses commandline options for manpath. manpath_parse_args() { local cmd_arg while getopts 'Ldq' cmd_arg; do case "${cmd_arg}" in L) Lflag=Lflag ;; d) debug=$(( $debug + 1 )) ;; q) qflag=qflag ;; *) manpath_usage ;; esac done >&2 } # Usage: manpath_usage # Display usage for the manpath(1) utility. manpath_usage() { echo 'usage: manpath [-Ldq]' >&2 exit 1 } # Usage: manpath_warnings # Display some warnings to stderr. manpath_warnings() { if [ -n "$Lflag" -a -n "$MANLOCALES" ]; then echo "(Warning: MANLOCALES environment variable set)" >&2 fi } # Usage: man_check_for_so page path # Returns: True if able to resolve the file, false if it ended in tears. # Detects the presence of the .so directive and causes the file to be # redirected to another source file. man_check_for_so() { local IFS line tstr unset IFS if [ -n "$catpage" ]; then return 0 fi # We need to loop to accommodate multiple .so directives. while true do line=$($cattool $manpage | head -1) case "$line" in .so*) trim "${line#.so}" decho "$manpage includes $tstr" # Glob and check for the file. if ! check_man "$path/$tstr*" ""; then decho " Unable to find $tstr" return 1 fi ;; *) break ;; esac done return 0 } # Usage: man_display_page # Display either the manpage or catpage depending on the use_cat variable man_display_page() { local IFS pipeline testline # We are called with IFS set to colon. This causes really weird # things to happen for the variables that have spaces in them. unset IFS # If we are supposed to use a catpage and we aren't using troff(1) # just zcat the catpage and we are done. if [ -z "$tflag" -a -n "$use_cat" ]; then if [ -n "$wflag" ]; then echo "$catpage (source: $manpage)" ret=0 else if [ $debug -gt 0 ]; then decho "Command: $cattool $catpage | $MANPAGER" ret=0 else eval "$cattool $catpage | $MANPAGER" ret=$? fi fi return fi # Okay, we are using the manpage, do we just need to output the # name of the manpage? if [ -n "$wflag" ]; then echo "$manpage" ret=0 return fi if [ -n "$use_width" ]; then mandoc_args="-O width=${use_width}" fi testline="mandoc -Tlint -Wunsupp >/dev/null 2>&1" if [ -n "$tflag" ]; then pipeline="mandoc -Tps $mandoc_args" else pipeline="mandoc $mandoc_args | $MANPAGER" fi if ! eval "$cattool $manpage | $testline" ;then if which -s groff; then man_display_page_groff else echo "This manpage needs groff(1) to be rendered" >&2 echo "First install groff(1): " >&2 echo "pkg install groff " >&2 ret=1 fi return fi if [ $debug -gt 0 ]; then decho "Command: $cattool $manpage | $pipeline" ret=0 else eval "$cattool $manpage | $pipeline" ret=$? fi } # Usage: man_display_page_groff # Display the manpage using groff man_display_page_groff() { local EQN NROFF PIC TBL TROFF REFER VGRIND local IFS l nroff_dev pipeline preproc_arg tool # So, we really do need to parse the manpage. First, figure out the # device flag (-T) we have to pass to eqn(1) and groff(1). Then, # setup the pipeline of commands based on the user's request. # If the manpage is from a particular charset, we need to setup nroff # to properly output for the correct device. case "${manpage}" in *.${man_charset}/*) # I don't pretend to know this; I'm just copying from the # previous version of man(1). case "$man_charset" in KOI8-R) nroff_dev="koi8-r" ;; ISO8859-1) nroff_dev="latin1" ;; ISO8859-15) nroff_dev="latin1" ;; UTF-8) nroff_dev="utf8" ;; *) nroff_dev="ascii" ;; esac NROFF="$NROFF -T$nroff_dev" EQN="$EQN -T$nroff_dev" # Iff the manpage is from the locale and not just the charset, # then we need to define the locale string. case "${manpage}" in */${man_lang}_${man_country}.${man_charset}/*) NROFF="$NROFF -dlocale=$man_lang.$man_charset" ;; */${man_lang}.${man_charset}/*) NROFF="$NROFF -dlocale=$man_lang.$man_charset" ;; esac # Allow language specific calls to override the default # set of utilities. l=$(echo $man_lang | tr [:lower:] [:upper:]) for tool in EQN NROFF PIC TBL TROFF REFER VGRIND; do eval "$tool=\${${tool}_$l:-\$$tool}" done ;; *) NROFF="$NROFF -Tascii" EQN="$EQN -Tascii" ;; esac if [ -z "$MANCOLOR" ]; then NROFF="$NROFF -P-c" fi if [ -n "${use_width}" ]; then NROFF="$NROFF -rLL=${use_width}n -rLT=${use_width}n" fi if [ -n "$MANROFFSEQ" ]; then set -- -$MANROFFSEQ while getopts 'egprtv' preproc_arg; do case "${preproc_arg}" in e) pipeline="$pipeline | $EQN" ;; g) ;; # Ignore for compatibility. p) pipeline="$pipeline | $PIC" ;; r) pipeline="$pipeline | $REFER" ;; t) pipeline="$pipeline | $TBL" ;; v) pipeline="$pipeline | $VGRIND" ;; *) usage ;; esac done # Strip the leading " | " from the resulting pipeline. pipeline="${pipeline#" | "}" else pipeline="$TBL" fi if [ -n "$tflag" ]; then pipeline="$pipeline | $TROFF" else pipeline="$pipeline | $NROFF | $MANPAGER" fi if [ $debug -gt 0 ]; then decho "Command: $cattool $manpage | $pipeline" ret=0 else eval "$cattool $manpage | $pipeline" ret=$? fi } # Usage: man_find_and_display page # Search through the manpaths looking for the given page. man_find_and_display() { local found_page locpath p path sect # Check to see if it's a file. But only if it has a '/' in # the filename. case "$1" in */*) if [ -f "$1" -a -r "$1" ]; then decho "Found a usable page, displaying that" unset use_cat manpage="$1" setup_cattool $manpage if man_check_for_so $manpage $(dirname $manpage); then found_page=yes man_display_page fi return fi ;; esac IFS=: for sect in $MANSECT; do decho "Searching section $sect" 2 for path in $MANPATH; do for locpath in $locpaths; do p=$path/$locpath p=${p%/.} # Rid ourselves of the trailing /. # Check if there is a MACHINE specific manpath. if find_file $p $sect $MACHINE "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi # Check if there is a MACHINE_ARCH # specific manpath. if find_file $p $sect $MACHINE_ARCH "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi # Check plain old manpath. if find_file $p $sect '' "$1"; then if man_check_for_so $manpage $p; then found_page=yes man_display_page if [ -n "$aflag" ]; then continue 2 else return fi fi fi done done done unset IFS # Nothing? Well, we are done then. if [ -z "$found_page" ]; then echo "No manual entry for $1" >&2 ret=1 return fi } # Usage: man_parse_args "$@" # Parses commandline options for man. man_parse_args() { local IFS cmd_arg while getopts 'M:P:S:adfhkm:op:tw' cmd_arg; do case "${cmd_arg}" in M) MANPATH=$OPTARG ;; P) MANPAGER=$OPTARG ;; S) MANSECT=$OPTARG ;; a) aflag=aflag ;; d) debug=$(( $debug + 1 )) ;; f) fflag=fflag ;; h) man_usage 0 ;; k) kflag=kflag ;; m) mflag=$OPTARG ;; o) oflag=oflag ;; p) MANROFFSEQ=$OPTARG ;; t) tflag=tflag ;; w) wflag=wflag ;; *) man_usage ;; esac done >&2 shift $(( $OPTIND - 1 )) # Check the args for incompatible options. case "${fflag}${kflag}${tflag}${wflag}" in fflagkflag*) echo "Incompatible options: -f and -k"; man_usage ;; fflag*tflag*) echo "Incompatible options: -f and -t"; man_usage ;; fflag*wflag) echo "Incompatible options: -f and -w"; man_usage ;; *kflagtflag*) echo "Incompatible options: -k and -t"; man_usage ;; *kflag*wflag) echo "Incompatible options: -k and -w"; man_usage ;; *tflagwflag) echo "Incompatible options: -t and -w"; man_usage ;; esac # Short circuit for whatis(1) and apropos(1) if [ -n "$fflag" ]; then do_whatis "$@" exit fi if [ -n "$kflag" ]; then do_apropos "$@" exit fi IFS=: for sect in $man_default_sections; do if [ "$sect" = "$1" ]; then decho "Detected manual section as first arg: $1" MANSECT="$1" shift break fi done unset IFS pages="$*" } # Usage: man_setup # Setup various trivial but essential variables. man_setup() { # Setup machine and architecture variables. if [ -n "$mflag" ]; then MACHINE_ARCH=${mflag%%:*} MACHINE=${mflag##*:} fi if [ -z "$MACHINE_ARCH" ]; then MACHINE_ARCH=$($SYSCTL -n hw.machine_arch) fi if [ -z "$MACHINE" ]; then MACHINE=$($SYSCTL -n hw.machine) fi decho "Using architecture: $MACHINE_ARCH:$MACHINE" setup_pager # Setup manual sections to search. if [ -z "$MANSECT" ]; then MANSECT=$man_default_sections fi decho "Using manual sections: $MANSECT" build_manpath man_setup_locale man_setup_width } # Usage: man_setup_width # Set up page width. man_setup_width() { local sizes unset use_width case "$MANWIDTH" in [0-9]*) if [ "$MANWIDTH" -gt 0 2>/dev/null ]; then use_width=$MANWIDTH fi ;; [Tt][Tt][Yy]) if { sizes=$($STTY size 0>&3 2>/dev/null); } 3>&1; then set -- $sizes if [ $2 -gt 80 ]; then use_width=$(($2-2)) fi fi ;; esac if [ -n "$use_width" ]; then decho "Using non-standard page width: ${use_width}" else decho 'Using standard page width' fi } # Usage: man_setup_locale # Setup necessary locale variables. man_setup_locale() { local lang_cc locpaths='.' man_charset='US-ASCII' # Setup locale information. if [ -n "$oflag" ]; then decho 'Using non-localized manpages' else # Use the locale tool to give us the proper LC_CTYPE eval $( $LOCALE ) case "$LC_CTYPE" in C) ;; POSIX) ;; [a-z][a-z]_[A-Z][A-Z]\.*) lang_cc="${LC_CTYPE%.*}" man_lang="${LC_CTYPE%_*}" man_country="${lang_cc#*_}" man_charset="${LC_CTYPE#*.}" locpaths="$LC_CTYPE" locpaths="$locpaths:$man_lang.$man_charset" if [ "$man_lang" != "en" ]; then locpaths="$locpaths:en.$man_charset" fi locpaths="$locpaths:." ;; *) echo 'Unknown locale, assuming C' >&2 ;; esac fi decho "Using locale paths: $locpaths" } # Usage: man_usage [exitcode] # Display usage for the man utility. man_usage() { echo 'Usage:' echo ' man [-adho] [-t | -w] [-M manpath] [-P pager] [-S mansect]' echo ' [-m arch[:machine]] [-p [eprtv]] [mansect] page [...]' echo ' man -f page [...] -- Emulates whatis(1)' echo ' man -k page [...] -- Emulates apropos(1)' # When exit'ing with -h, it's not an error. exit ${1:-1} } # Usage: parse_configs # Reads the end-user adjustable config files. parse_configs() { local IFS file files if [ -n "$parsed_configs" ]; then return fi unset IFS # Read the global config first in case the user wants # to override config_local. if [ -r "$config_global" ]; then parse_file "$config_global" fi # Glob the list of files to parse. set +f files=$(echo $config_local) set -f for file in $files; do if [ -r "$file" ]; then parse_file "$file" fi done parsed_configs='yes' } # Usage: parse_file file # Reads the specified config files. parse_file() { local file line tstr var file="$1" decho "Parsing config file: $file" while read line; do decho " $line" 2 case "$line" in \#*) decho " Comment" 3 ;; MANPATH*) decho " MANPATH" 3 trim "${line#MANPATH}" add_to_manpath "$tstr" ;; MANLOCALE*) decho " MANLOCALE" 3 trim "${line#MANLOCALE}" manlocales="$manlocales:$tstr" ;; MANCONFIG*) decho " MANCONFIG" 3 trim "${line#MANCONFIG}" config_local="$tstr" ;; # Set variables in the form of FOO_BAR *_*[\ \ ]*) var="${line%%[\ \ ]*}" trim "${line#$var}" eval "$var=\"$tstr\"" decho " Parsed $var" 3 ;; esac done < "$file" } # Usage: search_path # Traverse $PATH looking for manpaths. search_path() { local IFS p path decho "Searching PATH for man directories" IFS=: for path in $PATH; do if add_to_manpath "$path/man"; then : elif add_to_manpath "$path/MAN"; then : else case "$path" in */bin) p="${path%/bin}/share/man" add_to_manpath "$p" p="${path%/bin}/man" add_to_manpath "$p" ;; esac fi done unset IFS if [ -z "$manpath" ]; then decho ' Unable to find any manpaths, using default' manpath=$man_default_path fi } # Usage: search_whatis cmd [arglist] # Do the heavy lifting for apropos/whatis search_whatis() { local IFS bad cmd f good key keywords loc opt out path rval wlist cmd="$1" shift whatis_parse_args "$@" build_manpath build_manlocales setup_pager if [ "$cmd" = "whatis" ]; then opt="-w" fi f='whatis' IFS=: for path in $MANPATH; do if [ \! -d "$path" ]; then decho "Skipping non-existent path: $path" 2 continue fi if [ -f "$path/$f" -a -r "$path/$f" ]; then decho "Found whatis: $path/$f" wlist="$wlist $path/$f" fi for loc in $MANLOCALES; do if [ -f "$path/$loc/$f" -a -r "$path/$loc/$f" ]; then decho "Found whatis: $path/$loc/$f" wlist="$wlist $path/$loc/$f" fi done done unset IFS if [ -z "$wlist" ]; then echo "$cmd: no whatis databases in $MANPATH" >&2 exit 1 fi rval=0 for key in $keywords; do out=$(grep -Ehi $opt -- "$key" $wlist) if [ -n "$out" ]; then good="$good\\n$out" else bad="$bad\\n$key: nothing appropriate" rval=1 fi done # Strip leading carriage return. good=${good#\\n} bad=${bad#\\n} if [ -n "$good" ]; then echo -e "$good" | $MANPAGER fi if [ -n "$bad" ]; then echo -e "$bad" >&2 fi exit $rval } # Usage: setup_cattool page # Finds an appropriate decompressor based on extension setup_cattool() { case "$1" in *.bz) cattool='/usr/bin/bzcat' ;; *.bz2) cattool='/usr/bin/bzcat' ;; *.gz) cattool='/usr/bin/zcat' ;; *.lzma) cattool='/usr/bin/lzcat' ;; *.xz) cattool='/usr/bin/xzcat' ;; *) cattool='/usr/bin/zcat -f' ;; esac } # Usage: setup_pager # Correctly sets $MANPAGER setup_pager() { # Setup pager. if [ -z "$MANPAGER" ]; then if [ -n "$MANCOLOR" ]; then MANPAGER="less -sR" else if [ -n "$PAGER" ]; then MANPAGER="$PAGER" else - MANPAGER="more -s" + MANPAGER="less -s" fi fi fi decho "Using pager: $MANPAGER" } # Usage: trim string # Trims whitespace from beginning and end of a variable trim() { tstr=$1 while true; do case "$tstr" in [\ \ ]*) tstr="${tstr##[\ \ ]}" ;; *[\ \ ]) tstr="${tstr%%[\ \ ]}" ;; *) break ;; esac done } # Usage: whatis_parse_args "$@" # Parse commandline args for whatis and apropos. whatis_parse_args() { local cmd_arg while getopts 'd' cmd_arg; do case "${cmd_arg}" in d) debug=$(( $debug + 1 )) ;; *) whatis_usage ;; esac done >&2 shift $(( $OPTIND - 1 )) keywords="$*" } # Usage: whatis_usage # Display usage for the whatis/apropos utility. whatis_usage() { echo "usage: $cmd [-d] keyword [...]" exit 1 } # Supported commands do_apropos() { [ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/apropos) ] && \ exec apropos "$@" search_whatis apropos "$@" } do_man() { man_parse_args "$@" if [ -z "$pages" ]; then echo 'What manual page do you want?' >&2 exit 1 fi man_setup for page in $pages; do decho "Searching for $page" man_find_and_display "$page" done exit ${ret:-0} } do_manpath() { manpath_parse_args "$@" if [ -z "$qflag" ]; then manpath_warnings fi if [ -n "$Lflag" ]; then build_manlocales echo $MANLOCALES else build_manpath echo $MANPATH fi exit 0 } do_whatis() { [ $(stat -f %i /usr/bin/man) -ne $(stat -f %i /usr/bin/whatis) ] && \ exec whatis "$@" search_whatis whatis "$@" } # User's PATH setting decides on the groff-suite to pick up. EQN=eqn NROFF='groff -S -P-h -Wall -mtty-char -man' PIC=pic REFER=refer TBL=tbl TROFF='groff -S -man' VGRIND=vgrind LOCALE=/usr/bin/locale STTY=/bin/stty SYSCTL=/sbin/sysctl debug=0 man_default_sections='1:8:2:3:n:4:5:6:7:9:l' man_default_path='/usr/share/man:/usr/share/openssl/man:/usr/local/share/man:/usr/local/man' cattool='/usr/bin/zcat -f' config_global='/etc/man.conf' # This can be overridden via a setting in /etc/man.conf. config_local='/usr/local/etc/man.d/*.conf' # Set noglobbing for now. I don't want spurious globbing. set -f case "$0" in *apropos) do_apropos "$@" ;; *manpath) do_manpath "$@" ;; *whatis) do_whatis "$@" ;; *) do_man "$@" ;; esac Index: head/usr.bin/msgs/msgs.1 =================================================================== --- head/usr.bin/msgs/msgs.1 (revision 337496) +++ head/usr.bin/msgs/msgs.1 (revision 337497) @@ -1,232 +1,232 @@ .\" 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. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" @(#)msgs.1 8.2 (Berkeley) 4/28/95 .\" $FreeBSD$ .\" -.Dd April 28, 1995 +.Dd August 8, 2018 .Dt MSGS 1 .Os .Sh NAME .Nm msgs .Nd system messages and junk mail program .Sh SYNOPSIS .Nm .Op Fl fhlpq .Op Ar number .Op Ar \-number .Nm .Op Fl s .Nm .Op Fl c .Op \-days .Sh DESCRIPTION The .Nm utility is used to read system messages. These messages are sent by mailing to the login `msgs' and should be short pieces of information which are suitable to be read once by most users of the system. .Pp The .Nm utility is normally invoked each time you login, by placing it in the file .Pa .login (or .Pa .profile if you use .Xr sh 1 ) . It will then prompt you with the source and subject of each new message. If there is no subject line, the first few non-blank lines of the message will be displayed. If there is more to the message, you will be told how long it is and asked whether you wish to see the rest of the message. The possible responses are: .Bl -tag -width Fl .It Fl y Type the rest of the message. .It Ic RETURN Synonym for y. .It Fl n Skip this message and go on to the next message. .It Fl Redisplay the last message. .It Fl q Drop out of .Nm ; the next time .Nm will pick up where it last left off. .It Fl s Append the current message to the file ``Messages'' in the current directory; `s\-' will save the previously displayed message. A `s' or `s\-' may be followed by a space and a file name to receive the message replacing the default ``Messages''. .It Fl m A copy of the specified message is placed in a temporary mailbox and .Xr mail 1 is invoked on that mailbox. Both `m' and `s' accept a numeric argument in place of the `\-'. .El .Pp The .Nm utility keeps track of the next message you will see by a number in the file .Pa \&.msgsrc in your home directory. In the directory .Pa /var/msgs it keeps a set of files whose names are the (sequential) numbers of the messages they represent. The file .Pa /var/msgs/bounds shows the low and high number of the messages in the directory so that .Nm can quickly determine if there are no messages for you. If the contents of .Pa bounds is incorrect it can be fixed by removing it; .Nm will make a new .Pa bounds file the next time it is run with the .Fl s option. If .Nm is run with any option other than .Fl s , an error will be displayed if .Pa /var/msgs/bounds does not exist. .Pp The .Fl s option is used for setting up the posting of messages. The line .Pp .Dl msgs: \&"\&| /usr/bin/msgs \-s\&" .Pp should be included in .Pa /etc/mail/aliases (see .Xr newaliases 1 ) to enable posting of messages. .Pp The .Fl c option is used for performing cleanup on .Pa /var/msgs . A shell script entry to run .Nm with the .Fl c option should be placed in .Pa /etc/periodic/daily (see .Xr periodic 8 ) to run every night. This will remove all messages over 21 days old. A different expiration may be specified on the command line to override the default. You must be the superuser to use this option. .Pp Options when reading messages include: .Bl -tag -width Fl .It Fl f Do not say ``No new messages.''. This is useful in a .Pa .login file since this is often the case here. .It Fl q Queries whether there are messages, printing ``There are new messages.'' if there are. The command ``msgs \-q'' is often used in login scripts. .It Fl h Print the first part of messages only. .It Fl l Cause only locally originated messages to be reported. .It Ar num A message number can be given on the command line, causing .Nm to start at the specified message rather than at the next message indicated by your .Pa \&.msgsrc file. Thus .Pp .Dl msgs \-h 1 .Pp prints the first part of all messages. .It Ar \-number Start .Ar number messages back from the one indicated in the .Pa \&.msgsrc file, useful for reviews of recent messages. .It Fl p Pipe long messages through -.Xr more 1 . +.Xr less 1 . .El .Pp Within .Nm you can also go to any specific message by typing its number when .Nm requests input as to what to do. .Sh ENVIRONMENT The .Nm utility uses the .Ev HOME and .Ev TERM environment variables for the default home directory and terminal type. .Sh FILES .Bl -tag -width /var/msgs/* -compact .It Pa /var/msgs/* database .It Pa ~/.msgsrc number of next message to be presented .El .Sh SEE ALSO .Xr mail 1 , -.Xr more 1 , +.Xr less 1 , .Xr aliases 5 , .Xr periodic 8 .Sh HISTORY The .Nm command appeared in .Bx 3.0 . Index: head/usr.bin/msgs/pathnames.h =================================================================== --- head/usr.bin/msgs/pathnames.h (revision 337496) +++ head/usr.bin/msgs/pathnames.h (revision 337497) @@ -1,40 +1,40 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (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$ * * @(#)pathnames.h 8.1 (Berkeley) 6/6/93 */ #define _PATH_MSGS "/var/msgs" #define _PATH_MAIL "/usr/bin/Mail -f %s" -#define _PATH_PAGER "/usr/bin/more -%d" +#define _PATH_PAGER "/usr/bin/less -%d" #undef _PATH_TMP #define _PATH_TMP "/tmp/msgXXXXXX" Index: head/usr.sbin/freebsd-update/freebsd-update.sh =================================================================== --- head/usr.sbin/freebsd-update/freebsd-update.sh (revision 337496) +++ head/usr.sbin/freebsd-update/freebsd-update.sh (revision 337497) @@ -1,3312 +1,3312 @@ #!/bin/sh #- # SPDX-License-Identifier: BSD-2-Clause-FreeBSD # # Copyright 2004-2007 Colin Percival # All rights reserved # # Redistribution and use in source and binary forms, with or without # modification, are permitted providing that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING # IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # $FreeBSD$ #### Usage function -- called from command-line handling code. # Usage instructions. Options not listed: # --debug -- don't filter output from utilities # --no-stats -- don't show progress statistics while fetching files usage () { cat < ${LINE}" exit 1 fi done < ${CONFFILE} # Merge the settings read from the configuration file with those # provided at the command line. mergeconfig } # Provide some default parameters default_params () { # Save any parameters already configured, and clear the slate saveconfig nullconfig # Default configurations config_WorkDir /var/db/freebsd-update config_MailTo root config_AllowAdd yes config_AllowDelete yes config_KeepModifiedMetadata yes config_BaseDir / config_VerboseLevel stats config_StrictComponents no config_BackupKernel yes config_BackupKernelDir /boot/kernel.old config_BackupKernelSymbolFiles no # Merge these defaults into the earlier-configured settings mergeconfig } # Set utility output filtering options, based on ${VERBOSELEVEL} fetch_setup_verboselevel () { case ${VERBOSELEVEL} in debug) QUIETREDIR="/dev/stderr" QUIETFLAG=" " STATSREDIR="/dev/stderr" DDSTATS=".." XARGST="-t" NDEBUG=" " ;; nostats) QUIETREDIR="" QUIETFLAG="" STATSREDIR="/dev/null" DDSTATS=".." XARGST="" NDEBUG="" ;; stats) QUIETREDIR="/dev/null" QUIETFLAG="-q" STATSREDIR="/dev/stdout" DDSTATS="" XARGST="" NDEBUG="-n" ;; esac } # Perform sanity checks and set some final parameters # in preparation for fetching files. Figure out which # set of updates should be downloaded: If the user is # running *-p[0-9]+, strip off the last part; if the # user is running -SECURITY, call it -RELEASE. Chdir # into the working directory. fetchupgrade_check_params () { export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" _SERVERNAME_z=\ "SERVERNAME must be given via command line or configuration file." _KEYPRINT_z="Key must be given via -k option or configuration file." _KEYPRINT_bad="Invalid key fingerprint: " _WORKDIR_bad="Directory does not exist or is not writable: " _WORKDIR_bad2="Directory is not on a persistent filesystem: " if [ -z "${SERVERNAME}" ]; then echo -n "`basename $0`: " echo "${_SERVERNAME_z}" exit 1 fi if [ -z "${KEYPRINT}" ]; then echo -n "`basename $0`: " echo "${_KEYPRINT_z}" exit 1 fi if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then echo -n "`basename $0`: " echo -n "${_KEYPRINT_bad}" echo ${KEYPRINT} exit 1 fi if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then echo -n "`basename $0`: " echo -n "${_WORKDIR_bad}" echo ${WORKDIR} exit 1 fi case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*) echo -n "`basename $0`: " echo -n "${_WORKDIR_bad2}" echo ${WORKDIR} exit 1 ;; esac chmod 700 ${WORKDIR} cd ${WORKDIR} || exit 1 # Generate release number. The s/SECURITY/RELEASE/ bit exists # to provide an upgrade path for FreeBSD Update 1.x users, since # the kernels provided by FreeBSD Update 1.x are always labelled # as X.Y-SECURITY. RELNUM=`uname -r | sed -E 's,-p[0-9]+,,' | sed -E 's,-SECURITY,-RELEASE,'` ARCH=`uname -m` FETCHDIR=${RELNUM}/${ARCH} PATCHDIR=${RELNUM}/${ARCH}/bp # Figure out what directory contains the running kernel BOOTFILE=`sysctl -n kern.bootfile` KERNELDIR=${BOOTFILE%/kernel} if ! [ -d ${KERNELDIR} ]; then echo "Cannot identify running kernel" exit 1 fi # Figure out what kernel configuration is running. We start with # the output of `uname -i`, and then make the following adjustments: # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config # file says "ident SMP-GENERIC", I don't know... # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" # _and_ `sysctl kern.version` contains a line which ends "/SMP", then # we're running an SMP kernel. This mis-identification is a bug # which was fixed in 6.2-STABLE. KERNCONF=`uname -i` if [ ${KERNCONF} = "SMP-GENERIC" ]; then KERNCONF=SMP fi if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then if sysctl kern.version | grep -qE '/SMP$'; then KERNCONF=SMP fi fi # Define some paths BSPATCH=/usr/bin/bspatch SHA256=/sbin/sha256 PHTTPGET=/usr/libexec/phttpget # Set up variables relating to VERBOSELEVEL fetch_setup_verboselevel # Construct a unique name from ${BASEDIR} BDHASH=`echo ${BASEDIR} | sha256 -q` } # Perform sanity checks etc. before fetching updates. fetch_check_params () { fetchupgrade_check_params if ! [ -z "${TARGETRELEASE}" ]; then echo -n "`basename $0`: " echo -n "-r option is meaningless with 'fetch' command. " echo "(Did you mean 'upgrade' instead?)" exit 1 fi # Check that we have updates ready to install if [ -f ${BDHASH}-install/kerneldone -a $FORCEFETCH -eq 0 ]; then echo "You have a partially completed upgrade pending" echo "Run '$0 install' first." echo "Run '$0 fetch -F' to proceed anyway." exit 1 fi } # Perform sanity checks etc. before fetching upgrades. upgrade_check_params () { fetchupgrade_check_params # Unless set otherwise, we're upgrading to the same kernel config. NKERNCONF=${KERNCONF} # We need TARGETRELEASE set _TARGETRELEASE_z="Release target must be specified via -r option." if [ -z "${TARGETRELEASE}" ]; then echo -n "`basename $0`: " echo "${_TARGETRELEASE_z}" exit 1 fi # The target release should be != the current release. if [ "${TARGETRELEASE}" = "${RELNUM}" ]; then echo -n "`basename $0`: " echo "Cannot upgrade from ${RELNUM} to itself" exit 1 fi # Turning off AllowAdd or AllowDelete is a bad idea for upgrades. if [ "${ALLOWADD}" = "no" ]; then echo -n "`basename $0`: " echo -n "WARNING: \"AllowAdd no\" is a bad idea " echo "when upgrading between releases." echo fi if [ "${ALLOWDELETE}" = "no" ]; then echo -n "`basename $0`: " echo -n "WARNING: \"AllowDelete no\" is a bad idea " echo "when upgrading between releases." echo fi # Set EDITOR to /usr/bin/vi if it isn't already set : ${EDITOR:='/usr/bin/vi'} } # Perform sanity checks and set some final parameters in # preparation for installing updates. install_check_params () { # Check that we are root. All sorts of things won't work otherwise. if [ `id -u` != 0 ]; then echo "You must be root to run this." exit 1 fi # Check that securelevel <= 0. Otherwise we can't update schg files. if [ `sysctl -n kern.securelevel` -gt 0 ]; then echo "Updates cannot be installed when the system securelevel" echo "is greater than zero." exit 1 fi # Check that we have a working directory _WORKDIR_bad="Directory does not exist or is not writable: " if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then echo -n "`basename $0`: " echo -n "${_WORKDIR_bad}" echo ${WORKDIR} exit 1 fi cd ${WORKDIR} || exit 1 # Construct a unique name from ${BASEDIR} BDHASH=`echo ${BASEDIR} | sha256 -q` # Check that we have updates ready to install if ! [ -L ${BDHASH}-install ]; then echo "No updates are available to install." if [ $ISFETCHED -eq 0 ]; then echo "Run '$0 fetch' first." fi exit 0 fi if ! [ -f ${BDHASH}-install/INDEX-OLD ] || ! [ -f ${BDHASH}-install/INDEX-NEW ]; then echo "Update manifest is corrupt -- this should never happen." echo "Re-run '$0 fetch'." exit 1 fi # Figure out what directory contains the running kernel BOOTFILE=`sysctl -n kern.bootfile` KERNELDIR=${BOOTFILE%/kernel} if ! [ -d ${KERNELDIR} ]; then echo "Cannot identify running kernel" exit 1 fi } # Perform sanity checks and set some final parameters in # preparation for UNinstalling updates. rollback_check_params () { # Check that we are root. All sorts of things won't work otherwise. if [ `id -u` != 0 ]; then echo "You must be root to run this." exit 1 fi # Check that we have a working directory _WORKDIR_bad="Directory does not exist or is not writable: " if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then echo -n "`basename $0`: " echo -n "${_WORKDIR_bad}" echo ${WORKDIR} exit 1 fi cd ${WORKDIR} || exit 1 # Construct a unique name from ${BASEDIR} BDHASH=`echo ${BASEDIR} | sha256 -q` # Check that we have updates ready to rollback if ! [ -L ${BDHASH}-rollback ]; then echo "No rollback directory found." exit 1 fi if ! [ -f ${BDHASH}-rollback/INDEX-OLD ] || ! [ -f ${BDHASH}-rollback/INDEX-NEW ]; then echo "Update manifest is corrupt -- this should never happen." exit 1 fi } # Perform sanity checks and set some final parameters # in preparation for comparing the system against the # published index. Figure out which index we should # compare against: If the user is running *-p[0-9]+, # strip off the last part; if the user is running # -SECURITY, call it -RELEASE. Chdir into the working # directory. IDS_check_params () { export HTTP_USER_AGENT="freebsd-update (${COMMAND}, `uname -r`)" _SERVERNAME_z=\ "SERVERNAME must be given via command line or configuration file." _KEYPRINT_z="Key must be given via -k option or configuration file." _KEYPRINT_bad="Invalid key fingerprint: " _WORKDIR_bad="Directory does not exist or is not writable: " if [ -z "${SERVERNAME}" ]; then echo -n "`basename $0`: " echo "${_SERVERNAME_z}" exit 1 fi if [ -z "${KEYPRINT}" ]; then echo -n "`basename $0`: " echo "${_KEYPRINT_z}" exit 1 fi if ! echo "${KEYPRINT}" | grep -qE "^[0-9a-f]{64}$"; then echo -n "`basename $0`: " echo -n "${_KEYPRINT_bad}" echo ${KEYPRINT} exit 1 fi if ! [ -d "${WORKDIR}" -a -w "${WORKDIR}" ]; then echo -n "`basename $0`: " echo -n "${_WORKDIR_bad}" echo ${WORKDIR} exit 1 fi cd ${WORKDIR} || exit 1 # Generate release number. The s/SECURITY/RELEASE/ bit exists # to provide an upgrade path for FreeBSD Update 1.x users, since # the kernels provided by FreeBSD Update 1.x are always labelled # as X.Y-SECURITY. RELNUM=`uname -r | sed -E 's,-p[0-9]+,,' | sed -E 's,-SECURITY,-RELEASE,'` ARCH=`uname -m` FETCHDIR=${RELNUM}/${ARCH} PATCHDIR=${RELNUM}/${ARCH}/bp # Figure out what directory contains the running kernel BOOTFILE=`sysctl -n kern.bootfile` KERNELDIR=${BOOTFILE%/kernel} if ! [ -d ${KERNELDIR} ]; then echo "Cannot identify running kernel" exit 1 fi # Figure out what kernel configuration is running. We start with # the output of `uname -i`, and then make the following adjustments: # 1. Replace "SMP-GENERIC" with "SMP". Why the SMP kernel config # file says "ident SMP-GENERIC", I don't know... # 2. If the kernel claims to be GENERIC _and_ ${ARCH} is "amd64" # _and_ `sysctl kern.version` contains a line which ends "/SMP", then # we're running an SMP kernel. This mis-identification is a bug # which was fixed in 6.2-STABLE. KERNCONF=`uname -i` if [ ${KERNCONF} = "SMP-GENERIC" ]; then KERNCONF=SMP fi if [ ${KERNCONF} = "GENERIC" ] && [ ${ARCH} = "amd64" ]; then if sysctl kern.version | grep -qE '/SMP$'; then KERNCONF=SMP fi fi # Define some paths SHA256=/sbin/sha256 PHTTPGET=/usr/libexec/phttpget # Set up variables relating to VERBOSELEVEL fetch_setup_verboselevel } #### Core functionality -- the actual work gets done here # Use an SRV query to pick a server. If the SRV query doesn't provide # a useful answer, use the server name specified by the user. # Put another way... look up _http._tcp.${SERVERNAME} and pick a server # from that; or if no servers are returned, use ${SERVERNAME}. # This allows a user to specify "portsnap.freebsd.org" (in which case # portsnap will select one of the mirrors) or "portsnap5.tld.freebsd.org" # (in which case portsnap will use that particular server, since there # won't be an SRV entry for that name). # # We ignore the Port field, since we are always going to use port 80. # Fetch the mirror list, but do not pick a mirror yet. Returns 1 if # no mirrors are available for any reason. fetch_pick_server_init () { : > serverlist_tried # Check that host(1) exists (i.e., that the system wasn't built with the # WITHOUT_BIND set) and don't try to find a mirror if it doesn't exist. if ! which -s host; then : > serverlist_full return 1 fi echo -n "Looking up ${SERVERNAME} mirrors... " # Issue the SRV query and pull out the Priority, Weight, and Target fields. # BIND 9 prints "$name has SRV record ..." while BIND 8 prints # "$name server selection ..."; we allow either format. MLIST="_http._tcp.${SERVERNAME}" host -t srv "${MLIST}" | sed -nE "s/${MLIST} (has SRV record|server selection) //Ip" | cut -f 1,2,4 -d ' ' | sed -e 's/\.$//' | sort > serverlist_full # If no records, give up -- we'll just use the server name we were given. if [ `wc -l < serverlist_full` -eq 0 ]; then echo "none found." return 1 fi # Report how many mirrors we found. echo `wc -l < serverlist_full` "mirrors found." # Generate a random seed for use in picking mirrors. If HTTP_PROXY # is set, this will be used to generate the seed; otherwise, the seed # will be random. if [ -n "${HTTP_PROXY}${http_proxy}" ]; then RANDVALUE=`sha256 -qs "${HTTP_PROXY}${http_proxy}" | tr -d 'a-f' | cut -c 1-9` else RANDVALUE=`jot -r 1 0 999999999` fi } # Pick a mirror. Returns 1 if we have run out of mirrors to try. fetch_pick_server () { # Generate a list of not-yet-tried mirrors sort serverlist_tried | comm -23 serverlist_full - > serverlist # Have we run out of mirrors? if [ `wc -l < serverlist` -eq 0 ]; then echo "No mirrors remaining, giving up." return 1 fi # Find the highest priority level (lowest numeric value). SRV_PRIORITY=`cut -f 1 -d ' ' serverlist | sort -n | head -1` # Add up the weights of the response lines at that priority level. SRV_WSUM=0; while read X; do case "$X" in ${SRV_PRIORITY}\ *) SRV_W=`echo $X | cut -f 2 -d ' '` SRV_WSUM=$(($SRV_WSUM + $SRV_W)) ;; esac done < serverlist # If all the weights are 0, pretend that they are all 1 instead. if [ ${SRV_WSUM} -eq 0 ]; then SRV_WSUM=`grep -E "^${SRV_PRIORITY} " serverlist | wc -l` SRV_W_ADD=1 else SRV_W_ADD=0 fi # Pick a value between 0 and the sum of the weights - 1 SRV_RND=`expr ${RANDVALUE} % ${SRV_WSUM}` # Read through the list of mirrors and set SERVERNAME. Write the line # corresponding to the mirror we selected into serverlist_tried so that # we won't try it again. while read X; do case "$X" in ${SRV_PRIORITY}\ *) SRV_W=`echo $X | cut -f 2 -d ' '` SRV_W=$(($SRV_W + $SRV_W_ADD)) if [ $SRV_RND -lt $SRV_W ]; then SERVERNAME=`echo $X | cut -f 3 -d ' '` echo "$X" >> serverlist_tried break else SRV_RND=$(($SRV_RND - $SRV_W)) fi ;; esac done < serverlist } # Take a list of ${oldhash}|${newhash} and output a list of needed patches, # i.e., those for which we have ${oldhash} and don't have ${newhash}. fetch_make_patchlist () { grep -vE "^([0-9a-f]{64})\|\1$" | tr '|' ' ' | while read X Y; do if [ -f "files/${Y}.gz" ] || [ ! -f "files/${X}.gz" ]; then continue fi echo "${X}|${Y}" done | sort -u } # Print user-friendly progress statistics fetch_progress () { LNC=0 while read x; do LNC=$(($LNC + 1)) if [ $(($LNC % 10)) = 0 ]; then echo -n $LNC elif [ $(($LNC % 2)) = 0 ]; then echo -n . fi done echo -n " " } # Function for asking the user if everything is ok continuep () { while read -p "Does this look reasonable (y/n)? " CONTINUE; do case "${CONTINUE}" in y*) return 0 ;; n*) return 1 ;; esac done } # Initialize the working directory workdir_init () { mkdir -p files touch tINDEX.present } # Check that we have a public key with an appropriate hash, or # fetch the key if it doesn't exist. Returns 1 if the key has # not yet been fetched. fetch_key () { if [ -r pub.ssl ] && [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then return 0 fi echo -n "Fetching public key from ${SERVERNAME}... " rm -f pub.ssl fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/pub.ssl \ 2>${QUIETREDIR} || true if ! [ -r pub.ssl ]; then echo "failed." return 1 fi if ! [ `${SHA256} -q pub.ssl` = ${KEYPRINT} ]; then echo "key has incorrect hash." rm -f pub.ssl return 1 fi echo "done." } # Fetch metadata signature, aka "tag". fetch_tag () { echo -n "Fetching metadata signature " echo ${NDEBUG} "for ${RELNUM} from ${SERVERNAME}... " rm -f latest.ssl fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/latest.ssl \ 2>${QUIETREDIR} || true if ! [ -r latest.ssl ]; then echo "failed." return 1 fi openssl rsautl -pubin -inkey pub.ssl -verify \ < latest.ssl > tag.new 2>${QUIETREDIR} || true rm latest.ssl if ! [ `wc -l < tag.new` = 1 ] || ! grep -qE \ "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ tag.new; then echo "invalid signature." return 1 fi echo "done." RELPATCHNUM=`cut -f 4 -d '|' < tag.new` TINDEXHASH=`cut -f 5 -d '|' < tag.new` EOLTIME=`cut -f 6 -d '|' < tag.new` } # Sanity-check the patch number in a tag, to make sure that we're not # going to "update" backwards and to prevent replay attacks. fetch_tagsanity () { # Check that we're not going to move from -pX to -pY with Y < X. RELPX=`uname -r | sed -E 's,.*-,,'` if echo ${RELPX} | grep -qE '^p[0-9]+$'; then RELPX=`echo ${RELPX} | cut -c 2-` else RELPX=0 fi if [ "${RELPATCHNUM}" -lt "${RELPX}" ]; then echo echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" echo " appear older than what" echo "we are currently running (`uname -r`)!" echo "Cowardly refusing to proceed any further." return 1 fi # If "tag" exists and corresponds to ${RELNUM}, make sure that # it contains a patch number <= RELPATCHNUM, in order to protect # against rollback (replay) attacks. if [ -f tag ] && grep -qE \ "^freebsd-update\|${ARCH}\|${RELNUM}\|[0-9]+\|[0-9a-f]{64}\|[0-9]{10}" \ tag; then LASTRELPATCHNUM=`cut -f 4 -d '|' < tag` if [ "${RELPATCHNUM}" -lt "${LASTRELPATCHNUM}" ]; then echo echo -n "Files on mirror (${RELNUM}-p${RELPATCHNUM})" echo " are older than the" echo -n "most recently seen updates" echo " (${RELNUM}-p${LASTRELPATCHNUM})." echo "Cowardly refusing to proceed any further." return 1 fi fi } # Fetch metadata index file fetch_metadata_index () { echo ${NDEBUG} "Fetching metadata index... " rm -f ${TINDEXHASH} fetch ${QUIETFLAG} http://${SERVERNAME}/${FETCHDIR}/t/${TINDEXHASH} 2>${QUIETREDIR} if ! [ -f ${TINDEXHASH} ]; then echo "failed." return 1 fi if [ `${SHA256} -q ${TINDEXHASH}` != ${TINDEXHASH} ]; then echo "update metadata index corrupt." return 1 fi echo "done." } # Print an error message about signed metadata being bogus. fetch_metadata_bogus () { echo echo "The update metadata$1 is correctly signed, but" echo "failed an integrity check." echo "Cowardly refusing to proceed any further." return 1 } # Construct tINDEX.new by merging the lines named in $1 from ${TINDEXHASH} # with the lines not named in $@ from tINDEX.present (if that file exists). fetch_metadata_index_merge () { for METAFILE in $@; do if [ `grep -E "^${METAFILE}\|" ${TINDEXHASH} | wc -l` \ -ne 1 ]; then fetch_metadata_bogus " index" return 1 fi grep -E "${METAFILE}\|" ${TINDEXHASH} done | sort > tINDEX.wanted if [ -f tINDEX.present ]; then join -t '|' -v 2 tINDEX.wanted tINDEX.present | sort -m - tINDEX.wanted > tINDEX.new rm tINDEX.wanted else mv tINDEX.wanted tINDEX.new fi } # Sanity check all the lines of tINDEX.new. Even if more metadata lines # are added by future versions of the server, this won't cause problems, # since the only lines which appear in tINDEX.new are the ones which we # specifically grepped out of ${TINDEXHASH}. fetch_metadata_index_sanity () { if grep -qvE '^[0-9A-Z.-]+\|[0-9a-f]{64}$' tINDEX.new; then fetch_metadata_bogus " index" return 1 fi } # Sanity check the metadata file $1. fetch_metadata_sanity () { # Some aliases to save space later: ${P} is a character which can # appear in a path; ${M} is the four numeric metadata fields; and # ${H} is a sha256 hash. P="[-+./:=,%@_[~[:alnum:]]" M="[0-9]+\|[0-9]+\|[0-9]+\|[0-9]+" H="[0-9a-f]{64}" # Check that the first four fields make sense. if gunzip -c < files/$1.gz | grep -qvE "^[a-z]+\|[0-9a-z-]+\|${P}+\|[fdL-]\|"; then fetch_metadata_bogus "" return 1 fi # Remove the first three fields. gunzip -c < files/$1.gz | cut -f 4- -d '|' > sanitycheck.tmp # Sanity check entries with type 'f' if grep -E '^f' sanitycheck.tmp | grep -qvE "^f\|${M}\|${H}\|${P}*\$"; then fetch_metadata_bogus "" return 1 fi # Sanity check entries with type 'd' if grep -E '^d' sanitycheck.tmp | grep -qvE "^d\|${M}\|\|\$"; then fetch_metadata_bogus "" return 1 fi # Sanity check entries with type 'L' if grep -E '^L' sanitycheck.tmp | grep -qvE "^L\|${M}\|${P}*\|\$"; then fetch_metadata_bogus "" return 1 fi # Sanity check entries with type '-' if grep -E '^-' sanitycheck.tmp | grep -qvE "^-\|\|\|\|\|\|"; then fetch_metadata_bogus "" return 1 fi # Clean up rm sanitycheck.tmp } # Fetch the metadata index and metadata files listed in $@, # taking advantage of metadata patches where possible. fetch_metadata () { fetch_metadata_index || return 1 fetch_metadata_index_merge $@ || return 1 fetch_metadata_index_sanity || return 1 # Generate a list of wanted metadata patches join -t '|' -o 1.2,2.2 tINDEX.present tINDEX.new | fetch_make_patchlist > patchlist if [ -s patchlist ]; then # Attempt to fetch metadata patches echo -n "Fetching `wc -l < patchlist | tr -d ' '` " echo ${NDEBUG} "metadata patches.${DDSTATS}" tr '|' '-' < patchlist | lam -s "${FETCHDIR}/tp/" - -s ".gz" | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${STATSREDIR} | fetch_progress echo "done." # Attempt to apply metadata patches echo -n "Applying metadata patches... " tr '|' ' ' < patchlist | while read X Y; do if [ ! -f "${X}-${Y}.gz" ]; then continue; fi gunzip -c < ${X}-${Y}.gz > diff gunzip -c < files/${X}.gz > diff-OLD # Figure out which lines are being added and removed grep -E '^-' diff | cut -c 2- | while read PREFIX; do look "${PREFIX}" diff-OLD done | sort > diff-rm grep -E '^\+' diff | cut -c 2- > diff-add # Generate the new file comm -23 diff-OLD diff-rm | sort - diff-add > diff-NEW if [ `${SHA256} -q diff-NEW` = ${Y} ]; then mv diff-NEW files/${Y} gzip -n files/${Y} else mv diff-NEW ${Y}.bad fi rm -f ${X}-${Y}.gz diff rm -f diff-OLD diff-NEW diff-add diff-rm done 2>${QUIETREDIR} echo "done." fi # Update metadata without patches cut -f 2 -d '|' < tINDEX.new | while read Y; do if [ ! -f "files/${Y}.gz" ]; then echo ${Y}; fi done | sort -u > filelist if [ -s filelist ]; then echo -n "Fetching `wc -l < filelist | tr -d ' '` " echo ${NDEBUG} "metadata files... " lam -s "${FETCHDIR}/m/" - -s ".gz" < filelist | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${QUIETREDIR} while read Y; do if ! [ -f ${Y}.gz ]; then echo "failed." return 1 fi if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then mv ${Y}.gz files/${Y}.gz else echo "metadata is corrupt." return 1 fi done < filelist echo "done." fi # Sanity-check the metadata files. cut -f 2 -d '|' tINDEX.new > filelist while read X; do fetch_metadata_sanity ${X} || return 1 done < filelist # Remove files which are no longer needed cut -f 2 -d '|' tINDEX.present | sort > oldfiles cut -f 2 -d '|' tINDEX.new | sort | comm -13 - oldfiles | lam -s "files/" - -s ".gz" | xargs rm -f rm patchlist filelist oldfiles rm ${TINDEXHASH} # We're done! mv tINDEX.new tINDEX.present mv tag.new tag return 0 } # Extract a subset of a downloaded metadata file containing only the parts # which are listed in COMPONENTS. fetch_filter_metadata_components () { METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'` gunzip -c < files/${METAHASH}.gz > $1.all # Fish out the lines belonging to components we care about. for C in ${COMPONENTS}; do look "`echo ${C} | tr '/' '|'`|" $1.all done > $1 # Remove temporary file. rm $1.all } # Generate a filtered version of the metadata file $1 from the downloaded # file, by fishing out the lines corresponding to components we're trying # to keep updated, and then removing lines corresponding to paths we want # to ignore. fetch_filter_metadata () { # Fish out the lines belonging to components we care about. fetch_filter_metadata_components $1 # Canonicalize directory names by removing any trailing / in # order to avoid listing directories multiple times if they # belong to multiple components. Turning "/" into "" doesn't # matter, since we add a leading "/" when we use paths later. cut -f 3- -d '|' $1 | sed -e 's,/|d|,|d|,' | sed -e 's,/|-|,|-|,' | sort -u > $1.tmp # Figure out which lines to ignore and remove them. for X in ${IGNOREPATHS}; do grep -E "^${X}" $1.tmp done | sort -u | comm -13 - $1.tmp > $1 # Remove temporary files. rm $1.tmp } # Filter the metadata file $1 by adding lines with "/boot/$2" # replaced by ${KERNELDIR} (which is `sysctl -n kern.bootfile` minus the # trailing "/kernel"); and if "/boot/$2" does not exist, remove # the original lines which start with that. # Put another way: Deal with the fact that the FOO kernel is sometimes # installed in /boot/FOO/ and is sometimes installed elsewhere. fetch_filter_kernel_names () { grep ^/boot/$2 $1 | sed -e "s,/boot/$2,${KERNELDIR},g" | sort - $1 > $1.tmp mv $1.tmp $1 if ! [ -d /boot/$2 ]; then grep -v ^/boot/$2 $1 > $1.tmp mv $1.tmp $1 fi } # For all paths appearing in $1 or $3, inspect the system # and generate $2 describing what is currently installed. fetch_inspect_system () { # No errors yet... rm -f .err # Tell the user why his disk is suddenly making lots of noise echo -n "Inspecting system... " # Generate list of files to inspect cat $1 $3 | cut -f 1 -d '|' | sort -u > filelist # Examine each file and output lines of the form # /path/to/file|type|device-inum|user|group|perm|flags|value # sorted by device and inode number. while read F; do # If the symlink/file/directory does not exist, record this. if ! [ -e ${BASEDIR}/${F} ]; then echo "${F}|-||||||" continue fi if ! [ -r ${BASEDIR}/${F} ]; then echo "Cannot read file: ${BASEDIR}/${F}" \ >/dev/stderr touch .err return 1 fi # Otherwise, output an index line. if [ -L ${BASEDIR}/${F} ]; then echo -n "${F}|L|" stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; readlink ${BASEDIR}/${F}; elif [ -f ${BASEDIR}/${F} ]; then echo -n "${F}|f|" stat -n -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; sha256 -q ${BASEDIR}/${F}; elif [ -d ${BASEDIR}/${F} ]; then echo -n "${F}|d|" stat -f '%d-%i|%u|%g|%Mp%Lp|%Of|' ${BASEDIR}/${F}; else echo "Unknown file type: ${BASEDIR}/${F}" \ >/dev/stderr touch .err return 1 fi done < filelist | sort -k 3,3 -t '|' > $2.tmp rm filelist # Check if an error occurred during system inspection if [ -f .err ]; then return 1 fi # Convert to the form # /path/to/file|type|user|group|perm|flags|value|hlink # by resolving identical device and inode numbers into hard links. cut -f 1,3 -d '|' $2.tmp | sort -k 1,1 -t '|' | sort -s -u -k 2,2 -t '|' | join -1 2 -2 3 -t '|' - $2.tmp | awk -F \| -v OFS=\| \ '{ if (($2 == $3) || ($4 == "-")) print $3,$4,$5,$6,$7,$8,$9,"" else print $3,$4,$5,$6,$7,$8,$9,$2 }' | sort > $2 rm $2.tmp # We're finished looking around echo "done." } # For any paths matching ${MERGECHANGES}, compare $1 and $2 and find any # files which differ; generate $3 containing these paths and the old hashes. fetch_filter_mergechanges () { # Pull out the paths and hashes of the files matching ${MERGECHANGES}. for F in $1 $2; do for X in ${MERGECHANGES}; do grep -E "^${X}" ${F} done | cut -f 1,2,7 -d '|' | sort > ${F}-values done # Any line in $2-values which doesn't appear in $1-values and is a # file means that we should list the path in $3. comm -13 $1-values $2-values | fgrep '|f|' | cut -f 1 -d '|' > $2-paths # For each path, pull out one (and only one!) entry from $1-values. # Note that we cannot distinguish which "old" version the user made # changes to; but hopefully any changes which occur due to security # updates will exist in both the "new" version and the version which # the user has installed, so the merging will still work. while read X; do look "${X}|" $1-values | head -1 done < $2-paths > $3 # Clean up rm $1-values $2-values $2-paths } # For any paths matching ${UPDATEIFUNMODIFIED}, remove lines from $[123] # which correspond to lines in $2 with hashes not matching $1 or $3, unless # the paths are listed in $4. For entries in $2 marked "not present" # (aka. type -), remove lines from $[123] unless there is a corresponding # entry in $1. fetch_filter_unmodified_notpresent () { # Figure out which lines of $1 and $3 correspond to bits which # should only be updated if they haven't changed, and fish out # the (path, type, value) tuples. # NOTE: We don't consider a file to be "modified" if it matches # the hash from $3. for X in ${UPDATEIFUNMODIFIED}; do grep -E "^${X}" $1 grep -E "^${X}" $3 done | cut -f 1,2,7 -d '|' | sort > $1-values # Do the same for $2. for X in ${UPDATEIFUNMODIFIED}; do grep -E "^${X}" $2 done | cut -f 1,2,7 -d '|' | sort > $2-values # Any entry in $2-values which is not in $1-values corresponds to # a path which we need to remove from $1, $2, and $3, unless it # that path appears in $4. comm -13 $1-values $2-values | sort -t '|' -k 1,1 > mlines.tmp cut -f 1 -d '|' $4 | sort | join -v 2 -t '|' - mlines.tmp | sort > mlines rm $1-values $2-values mlines.tmp # Any lines in $2 which are not in $1 AND are "not present" lines # also belong in mlines. comm -13 $1 $2 | cut -f 1,2,7 -d '|' | fgrep '|-|' >> mlines # Remove lines from $1, $2, and $3 for X in $1 $2 $3; do sort -t '|' -k 1,1 ${X} > ${X}.tmp cut -f 1 -d '|' < mlines | sort | join -v 2 -t '|' - ${X}.tmp | sort > ${X} rm ${X}.tmp done # Store a list of the modified files, for future reference fgrep -v '|-|' mlines | cut -f 1 -d '|' > modifiedfiles rm mlines } # For each entry in $1 of type -, remove any corresponding # entry from $2 if ${ALLOWADD} != "yes". Remove all entries # of type - from $1. fetch_filter_allowadd () { cut -f 1,2 -d '|' < $1 | fgrep '|-' | cut -f 1 -d '|' > filesnotpresent if [ ${ALLOWADD} != "yes" ]; then sort < $2 | join -v 1 -t '|' - filesnotpresent | sort > $2.tmp mv $2.tmp $2 fi sort < $1 | join -v 1 -t '|' - filesnotpresent | sort > $1.tmp mv $1.tmp $1 rm filesnotpresent } # If ${ALLOWDELETE} != "yes", then remove any entries from $1 # which don't correspond to entries in $2. fetch_filter_allowdelete () { # Produce a lists ${PATH}|${TYPE} for X in $1 $2; do cut -f 1-2 -d '|' < ${X} | sort -u > ${X}.nodes done # Figure out which lines need to be removed from $1. if [ ${ALLOWDELETE} != "yes" ]; then comm -23 $1.nodes $2.nodes > $1.badnodes else : > $1.badnodes fi # Remove the relevant lines from $1 while read X; do look "${X}|" $1 done < $1.badnodes | comm -13 - $1 > $1.tmp mv $1.tmp $1 rm $1.badnodes $1.nodes $2.nodes } # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in $2 # with metadata not matching any entry in $1, replace the corresponding # line of $3 with one having the same metadata as the entry in $2. fetch_filter_modified_metadata () { # Fish out the metadata from $1 and $2 for X in $1 $2; do cut -f 1-6 -d '|' < ${X} > ${X}.metadata done # Find the metadata we need to keep if [ ${KEEPMODIFIEDMETADATA} = "yes" ]; then comm -13 $1.metadata $2.metadata > keepmeta else : > keepmeta fi # Extract the lines which we need to remove from $3, and # construct the lines which we need to add to $3. : > $3.remove : > $3.add while read LINE; do NODE=`echo "${LINE}" | cut -f 1-2 -d '|'` look "${NODE}|" $3 >> $3.remove look "${NODE}|" $3 | cut -f 7- -d '|' | lam -s "${LINE}|" - >> $3.add done < keepmeta # Remove the specified lines and add the new lines. sort $3.remove | comm -13 - $3 | sort -u - $3.add > $3.tmp mv $3.tmp $3 rm keepmeta $1.metadata $2.metadata $3.add $3.remove } # Remove lines from $1 and $2 which are identical; # no need to update a file if it isn't changing. fetch_filter_uptodate () { comm -23 $1 $2 > $1.tmp comm -13 $1 $2 > $2.tmp mv $1.tmp $1 mv $2.tmp $2 } # Fetch any "clean" old versions of files we need for merging changes. fetch_files_premerge () { # We only need to do anything if $1 is non-empty. if [ -s $1 ]; then # Tell the user what we're doing echo -n "Fetching files from ${OLDRELNUM} for merging... " # List of files wanted fgrep '|f|' < $1 | cut -f 3 -d '|' | sort -u > files.wanted # Only fetch the files we don't already have while read Y; do if [ ! -f "files/${Y}.gz" ]; then echo ${Y}; fi done < files.wanted > filelist # Actually fetch them lam -s "${OLDFETCHDIR}/f/" - -s ".gz" < filelist | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${QUIETREDIR} # Make sure we got them all, and move them into /files/ while read Y; do if ! [ -f ${Y}.gz ]; then echo "failed." return 1 fi if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then mv ${Y}.gz files/${Y}.gz else echo "${Y} has incorrect hash." return 1 fi done < filelist echo "done." # Clean up rm filelist files.wanted fi } # Prepare to fetch files: Generate a list of the files we need, # copy the unmodified files we have into /files/, and generate # a list of patches to download. fetch_files_prepare () { # Tell the user why his disk is suddenly making lots of noise echo -n "Preparing to download files... " # Reduce indices to ${PATH}|${HASH} pairs for X in $1 $2 $3; do cut -f 1,2,7 -d '|' < ${X} | fgrep '|f|' | cut -f 1,3 -d '|' | sort > ${X}.hashes done # List of files wanted cut -f 2 -d '|' < $3.hashes | sort -u | while read HASH; do if ! [ -f files/${HASH}.gz ]; then echo ${HASH} fi done > files.wanted # Generate a list of unmodified files comm -12 $1.hashes $2.hashes | sort -k 1,1 -t '|' > unmodified.files # Copy all files into /files/. We only need the unmodified files # for use in patching; but we'll want all of them if the user asks # to rollback the updates later. while read LINE; do F=`echo "${LINE}" | cut -f 1 -d '|'` HASH=`echo "${LINE}" | cut -f 2 -d '|'` # Skip files we already have. if [ -f files/${HASH}.gz ]; then continue fi # Make sure the file hasn't changed. cp "${BASEDIR}/${F}" tmpfile if [ `sha256 -q tmpfile` != ${HASH} ]; then echo echo "File changed while FreeBSD Update running: ${F}" return 1 fi # Place the file into storage. gzip -c < tmpfile > files/${HASH}.gz rm tmpfile done < $2.hashes # Produce a list of patches to download sort -k 1,1 -t '|' $3.hashes | join -t '|' -o 2.2,1.2 - unmodified.files | fetch_make_patchlist > patchlist # Garbage collect rm unmodified.files $1.hashes $2.hashes $3.hashes # We don't need the list of possible old files any more. rm $1 # We're finished making noise echo "done." } # Fetch files. fetch_files () { # Attempt to fetch patches if [ -s patchlist ]; then echo -n "Fetching `wc -l < patchlist | tr -d ' '` " echo ${NDEBUG} "patches.${DDSTATS}" tr '|' '-' < patchlist | lam -s "${PATCHDIR}/" - | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${STATSREDIR} | fetch_progress echo "done." # Attempt to apply patches echo -n "Applying patches... " tr '|' ' ' < patchlist | while read X Y; do if [ ! -f "${X}-${Y}" ]; then continue; fi gunzip -c < files/${X}.gz > OLD bspatch OLD NEW ${X}-${Y} if [ `${SHA256} -q NEW` = ${Y} ]; then mv NEW files/${Y} gzip -n files/${Y} fi rm -f diff OLD NEW ${X}-${Y} done 2>${QUIETREDIR} echo "done." fi # Download files which couldn't be generate via patching while read Y; do if [ ! -f "files/${Y}.gz" ]; then echo ${Y}; fi done < files.wanted > filelist if [ -s filelist ]; then echo -n "Fetching `wc -l < filelist | tr -d ' '` " echo ${NDEBUG} "files... " lam -s "${FETCHDIR}/f/" - -s ".gz" < filelist | xargs ${XARGST} ${PHTTPGET} ${SERVERNAME} \ 2>${QUIETREDIR} while read Y; do if ! [ -f ${Y}.gz ]; then echo "failed." return 1 fi if [ `gunzip -c < ${Y}.gz | ${SHA256} -q` = ${Y} ]; then mv ${Y}.gz files/${Y}.gz else echo "${Y} has incorrect hash." return 1 fi done < filelist echo "done." fi # Clean up rm files.wanted filelist patchlist } # Create and populate install manifest directory; and report what updates # are available. fetch_create_manifest () { # If we have an existing install manifest, nuke it. if [ -L "${BDHASH}-install" ]; then rm -r ${BDHASH}-install/ rm ${BDHASH}-install fi # Report to the user if any updates were avoided due to local changes if [ -s modifiedfiles ]; then echo echo -n "The following files are affected by updates, " echo "but no changes have" echo -n "been downloaded because the files have been " echo "modified locally:" cat modifiedfiles fi | $PAGER rm modifiedfiles # If no files will be updated, tell the user and exit if ! [ -s INDEX-PRESENT ] && ! [ -s INDEX-NEW ]; then rm INDEX-PRESENT INDEX-NEW echo echo -n "No updates needed to update system to " echo "${RELNUM}-p${RELPATCHNUM}." return fi # Divide files into (a) removed files, (b) added files, and # (c) updated files. cut -f 1 -d '|' < INDEX-PRESENT | sort > INDEX-PRESENT.flist cut -f 1 -d '|' < INDEX-NEW | sort > INDEX-NEW.flist comm -23 INDEX-PRESENT.flist INDEX-NEW.flist > files.removed comm -13 INDEX-PRESENT.flist INDEX-NEW.flist > files.added comm -12 INDEX-PRESENT.flist INDEX-NEW.flist > files.updated rm INDEX-PRESENT.flist INDEX-NEW.flist # Report removed files, if any if [ -s files.removed ]; then echo echo -n "The following files will be removed " echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" cat files.removed fi | $PAGER rm files.removed # Report added files, if any if [ -s files.added ]; then echo echo -n "The following files will be added " echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" cat files.added fi | $PAGER rm files.added # Report updated files, if any if [ -s files.updated ]; then echo echo -n "The following files will be updated " echo "as part of updating to ${RELNUM}-p${RELPATCHNUM}:" cat files.updated fi | $PAGER rm files.updated # Create a directory for the install manifest. MDIR=`mktemp -d install.XXXXXX` || return 1 # Populate it mv INDEX-PRESENT ${MDIR}/INDEX-OLD mv INDEX-NEW ${MDIR}/INDEX-NEW # Link it into place ln -s ${MDIR} ${BDHASH}-install } # Warn about any upcoming EoL fetch_warn_eol () { # What's the current time? NOWTIME=`date "+%s"` # When did we last warn about the EoL date? if [ -f lasteolwarn ]; then LASTWARN=`cat lasteolwarn` else LASTWARN=`expr ${NOWTIME} - 63072000` fi # If the EoL time is past, warn. if [ ${EOLTIME} -lt ${NOWTIME} ]; then echo cat <<-EOF WARNING: `uname -sr` HAS PASSED ITS END-OF-LIFE DATE. Any security issues discovered after `date -r ${EOLTIME}` will not have been corrected. EOF return 1 fi # Figure out how long it has been since we last warned about the # upcoming EoL, and how much longer we have left. SINCEWARN=`expr ${NOWTIME} - ${LASTWARN}` TIMELEFT=`expr ${EOLTIME} - ${NOWTIME}` # Don't warn if the EoL is more than 3 months away if [ ${TIMELEFT} -gt 7884000 ]; then return 0 fi # Don't warn if the time remaining is more than 3 times the time # since the last warning. if [ ${TIMELEFT} -gt `expr ${SINCEWARN} \* 3` ]; then return 0 fi # Figure out what time units to use. if [ ${TIMELEFT} -lt 604800 ]; then UNIT="day" SIZE=86400 elif [ ${TIMELEFT} -lt 2678400 ]; then UNIT="week" SIZE=604800 else UNIT="month" SIZE=2678400 fi # Compute the right number of units NUM=`expr ${TIMELEFT} / ${SIZE}` if [ ${NUM} != 1 ]; then UNIT="${UNIT}s" fi # Print the warning echo cat <<-EOF WARNING: `uname -sr` is approaching its End-of-Life date. It is strongly recommended that you upgrade to a newer release within the next ${NUM} ${UNIT}. EOF # Update the stored time of last warning echo ${NOWTIME} > lasteolwarn } # Do the actual work involved in "fetch" / "cron". fetch_run () { workdir_init || return 1 # Prepare the mirror list. fetch_pick_server_init && fetch_pick_server # Try to fetch the public key until we run out of servers. while ! fetch_key; do fetch_pick_server || return 1 done # Try to fetch the metadata index signature ("tag") until we run # out of available servers; and sanity check the downloaded tag. while ! fetch_tag; do fetch_pick_server || return 1 done fetch_tagsanity || return 1 # Fetch the latest INDEX-NEW and INDEX-OLD files. fetch_metadata INDEX-NEW INDEX-OLD || return 1 # Generate filtered INDEX-NEW and INDEX-OLD files containing only # the lines which (a) belong to components we care about, and (b) # don't correspond to paths we're explicitly ignoring. fetch_filter_metadata INDEX-NEW || return 1 fetch_filter_metadata INDEX-OLD || return 1 # Translate /boot/${KERNCONF} into ${KERNELDIR} fetch_filter_kernel_names INDEX-NEW ${KERNCONF} fetch_filter_kernel_names INDEX-OLD ${KERNCONF} # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the # system and generate an INDEX-PRESENT file. fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which # correspond to lines in INDEX-PRESENT with hashes not appearing # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in # INDEX-PRESENT has type - and there isn't a corresponding entry in # INDEX-OLD with type -. fetch_filter_unmodified_notpresent \ INDEX-OLD INDEX-PRESENT INDEX-NEW /dev/null # For each entry in INDEX-PRESENT of type -, remove any corresponding # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries # of type - from INDEX-PRESENT. fetch_filter_allowadd INDEX-PRESENT INDEX-NEW # If ${ALLOWDELETE} != "yes", then remove any entries from # INDEX-PRESENT which don't correspond to entries in INDEX-NEW. fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD, # replace the corresponding line of INDEX-NEW with one having the # same metadata as the entry in INDEX-PRESENT. fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical; # no need to update a file if it isn't changing. fetch_filter_uptodate INDEX-PRESENT INDEX-NEW # Prepare to fetch files: Generate a list of the files we need, # copy the unmodified files we have into /files/, and generate # a list of patches to download. fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 # Fetch files. fetch_files || return 1 # Create and populate install manifest directory; and report what # updates are available. fetch_create_manifest || return 1 # Warn about any upcoming EoL fetch_warn_eol || return 1 } # If StrictComponents is not "yes", generate a new components list # with only the components which appear to be installed. upgrade_guess_components () { if [ "${STRICTCOMPONENTS}" = "no" ]; then # Generate filtered INDEX-ALL with only the components listed # in COMPONENTS. fetch_filter_metadata_components $1 || return 1 # Tell the user why his disk is suddenly making lots of noise echo -n "Inspecting system... " # Look at the files on disk, and assume that a component is # supposed to be present if it is more than half-present. cut -f 1-3 -d '|' < INDEX-ALL | tr '|' ' ' | while read C S F; do if [ -e ${BASEDIR}/${F} ]; then echo "+ ${C}|${S}" fi echo "= ${C}|${S}" done | sort | uniq -c | sed -E 's,^ +,,' > compfreq grep ' = ' compfreq | cut -f 1,3 -d ' ' | sort -k 2,2 -t ' ' > compfreq.total grep ' + ' compfreq | cut -f 1,3 -d ' ' | sort -k 2,2 -t ' ' > compfreq.present join -t ' ' -1 2 -2 2 compfreq.present compfreq.total | while read S P T; do if [ ${P} -gt `expr ${T} / 2` ]; then echo ${S} fi done > comp.present cut -f 2 -d ' ' < compfreq.total > comp.total rm INDEX-ALL compfreq compfreq.total compfreq.present # We're done making noise. echo "done." # Sometimes the kernel isn't installed where INDEX-ALL # thinks that it should be: In particular, it is often in # /boot/kernel instead of /boot/GENERIC or /boot/SMP. To # deal with this, if "kernel|X" is listed in comp.total # (i.e., is a component which would be upgraded if it is # found to be present) we will add it to comp.present. # If "kernel|" is in comp.total but "kernel|X" is # not, we print a warning -- the user is running a kernel # which isn't part of the release. KCOMP=`echo ${KERNCONF} | tr 'A-Z' 'a-z'` grep -E "^kernel\|${KCOMP}\$" comp.total >> comp.present if grep -qE "^kernel\|" comp.total && ! grep -qE "^kernel\|${KCOMP}\$" comp.total; then cat <<-EOF WARNING: This system is running a "${KCOMP}" kernel, which is not a kernel configuration distributed as part of FreeBSD ${RELNUM}. This kernel will not be updated: you MUST update the kernel manually before running "$0 install". EOF fi # Re-sort the list of installed components and generate # the list of non-installed components. sort -u < comp.present > comp.present.tmp mv comp.present.tmp comp.present comm -13 comp.present comp.total > comp.absent # Ask the user to confirm that what we have is correct. To # reduce user confusion, translate "X|Y" back to "X/Y" (as # subcomponents must be listed in the configuration file). echo echo -n "The following components of FreeBSD " echo "seem to be installed:" tr '|' '/' < comp.present | fmt -72 echo echo -n "The following components of FreeBSD " echo "do not seem to be installed:" tr '|' '/' < comp.absent | fmt -72 echo continuep || return 1 echo # Suck the generated list of components into ${COMPONENTS}. # Note that comp.present.tmp is used due to issues with # pipelines and setting variables. COMPONENTS="" tr '|' '/' < comp.present > comp.present.tmp while read C; do COMPONENTS="${COMPONENTS} ${C}" done < comp.present.tmp # Delete temporary files rm comp.present comp.present.tmp comp.absent comp.total fi } # If StrictComponents is not "yes", COMPONENTS contains an entry # corresponding to the currently running kernel, and said kernel # does not exist in the new release, add "kernel/generic" to the # list of components. upgrade_guess_new_kernel () { if [ "${STRICTCOMPONENTS}" = "no" ]; then # Grab the unfiltered metadata file. METAHASH=`look "$1|" tINDEX.present | cut -f 2 -d '|'` gunzip -c < files/${METAHASH}.gz > $1.all # If "kernel/${KCOMP}" is in ${COMPONENTS} and that component # isn't in $1.all, we need to add kernel/generic. for C in ${COMPONENTS}; do if [ ${C} = "kernel/${KCOMP}" ] && ! grep -qE "^kernel\|${KCOMP}\|" $1.all; then COMPONENTS="${COMPONENTS} kernel/generic" NKERNCONF="GENERIC" cat <<-EOF WARNING: This system is running a "${KCOMP}" kernel, which is not a kernel configuration distributed as part of FreeBSD ${RELNUM}. As part of upgrading to FreeBSD ${RELNUM}, this kernel will be replaced with a "generic" kernel. EOF continuep || return 1 fi done # Don't need this any more... rm $1.all fi } # Convert INDEX-OLD (last release) and INDEX-ALL (new release) into # INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades). upgrade_oldall_to_oldnew () { # For each ${F}|... which appears in INDEX-ALL but does not appear # in INDEX-OLD, add ${F}|-|||||| to INDEX-OLD. cut -f 1 -d '|' < $1 | sort -u > $1.paths cut -f 1 -d '|' < $2 | sort -u | comm -13 $1.paths - | lam - -s "|-||||||" | sort - $1 > $1.tmp mv $1.tmp $1 # Remove lines from INDEX-OLD which also appear in INDEX-ALL comm -23 $1 $2 > $1.tmp mv $1.tmp $1 # Remove lines from INDEX-ALL which have a file name not appearing # anywhere in INDEX-OLD (since these must be files which haven't # changed -- if they were new, there would be an entry of type "-"). cut -f 1 -d '|' < $1 | sort -u > $1.paths sort -k 1,1 -t '|' < $2 | join -t '|' - $1.paths | sort > $2.tmp rm $1.paths mv $2.tmp $2 # Rename INDEX-ALL to INDEX-NEW. mv $2 $3 } # Helper for upgrade_merge: Return zero true iff the two files differ only # in the contents of their RCS tags. samef () { X=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $1 | ${SHA256}` Y=`sed -E 's/\\$FreeBSD.*\\$/\$FreeBSD\$/' < $2 | ${SHA256}` if [ $X = $Y ]; then return 0; else return 1; fi } # From the list of "old" files in $1, merge changes in $2 with those in $3, # and update $3 to reflect the hashes of merged files. upgrade_merge () { # We only need to do anything if $1 is non-empty. if [ -s $1 ]; then cut -f 1 -d '|' $1 | sort > $1-paths # Create staging area for merging files rm -rf merge/ while read F; do D=`dirname ${F}` mkdir -p merge/old/${D} mkdir -p merge/${OLDRELNUM}/${D} mkdir -p merge/${RELNUM}/${D} mkdir -p merge/new/${D} done < $1-paths # Copy in files while read F; do # Currently installed file V=`look "${F}|" $2 | cut -f 7 -d '|'` gunzip < files/${V}.gz > merge/old/${F} # Old release if look "${F}|" $1 | fgrep -q "|f|"; then V=`look "${F}|" $1 | cut -f 3 -d '|'` gunzip < files/${V}.gz \ > merge/${OLDRELNUM}/${F} fi # New release if look "${F}|" $3 | cut -f 1,2,7 -d '|' | fgrep -q "|f|"; then V=`look "${F}|" $3 | cut -f 7 -d '|'` gunzip < files/${V}.gz \ > merge/${RELNUM}/${F} fi done < $1-paths # Attempt to automatically merge changes echo -n "Attempting to automatically merge " echo -n "changes in files..." : > failed.merges while read F; do # If the file doesn't exist in the new release, # the result of "merging changes" is having the file # not exist. if ! [ -f merge/${RELNUM}/${F} ]; then continue fi # If the file didn't exist in the old release, we're # going to throw away the existing file and hope that # the version from the new release is what we want. if ! [ -f merge/${OLDRELNUM}/${F} ]; then cp merge/${RELNUM}/${F} merge/new/${F} continue fi # Some files need special treatment. case ${F} in /etc/spwd.db | /etc/pwd.db | /etc/login.conf.db) # Don't merge these -- we're rebuild them # after updates are installed. cp merge/old/${F} merge/new/${F} ;; *) if ! diff3 -E -m -L "current version" \ -L "${OLDRELNUM}" -L "${RELNUM}" \ merge/old/${F} \ merge/${OLDRELNUM}/${F} \ merge/${RELNUM}/${F} \ > merge/new/${F} 2>/dev/null; then echo ${F} >> failed.merges fi ;; esac done < $1-paths echo " done." # Ask the user to handle any files which didn't merge. while read F; do # If the installed file differs from the version in # the old release only due to RCS tag expansion # then just use the version in the new release. if samef merge/old/${F} merge/${OLDRELNUM}/${F}; then cp merge/${RELNUM}/${F} merge/new/${F} continue fi cat <<-EOF The following file could not be merged automatically: ${F} Press Enter to edit this file in ${EDITOR} and resolve the conflicts manually... EOF read dummy files/${V}.gz echo "${F}|${V}" fi done < $1-paths > newhashes # Pull lines out from $3 which need to be updated to # reflect merged files. while read F; do look "${F}|" $3 done < $1-paths > $3-oldlines # Update lines to reflect merged files join -t '|' -o 1.1,1.2,1.3,1.4,1.5,1.6,2.2,1.8 \ $3-oldlines newhashes > $3-newlines # Remove old lines from $3 and add new lines. sort $3-oldlines | comm -13 - $3 | sort - $3-newlines > $3.tmp mv $3.tmp $3 # Clean up rm $1-paths newhashes $3-oldlines $3-newlines rm -rf merge/ fi # We're done with merging files. rm $1 } # Do the work involved in fetching upgrades to a new release upgrade_run () { workdir_init || return 1 # Prepare the mirror list. fetch_pick_server_init && fetch_pick_server # Try to fetch the public key until we run out of servers. while ! fetch_key; do fetch_pick_server || return 1 done # Try to fetch the metadata index signature ("tag") until we run # out of available servers; and sanity check the downloaded tag. while ! fetch_tag; do fetch_pick_server || return 1 done fetch_tagsanity || return 1 # Fetch the INDEX-OLD and INDEX-ALL. fetch_metadata INDEX-OLD INDEX-ALL || return 1 # If StrictComponents is not "yes", generate a new components list # with only the components which appear to be installed. upgrade_guess_components INDEX-ALL || return 1 # Generate filtered INDEX-OLD and INDEX-ALL files containing only # the components we want and without anything marked as "Ignore". fetch_filter_metadata INDEX-OLD || return 1 fetch_filter_metadata INDEX-ALL || return 1 # Merge the INDEX-OLD and INDEX-ALL files into INDEX-OLD. sort INDEX-OLD INDEX-ALL > INDEX-OLD.tmp mv INDEX-OLD.tmp INDEX-OLD rm INDEX-ALL # Adjust variables for fetching files from the new release. OLDRELNUM=${RELNUM} RELNUM=${TARGETRELEASE} OLDFETCHDIR=${FETCHDIR} FETCHDIR=${RELNUM}/${ARCH} # Try to fetch the NEW metadata index signature ("tag") until we run # out of available servers; and sanity check the downloaded tag. while ! fetch_tag; do fetch_pick_server || return 1 done # Fetch the new INDEX-ALL. fetch_metadata INDEX-ALL || return 1 # If StrictComponents is not "yes", COMPONENTS contains an entry # corresponding to the currently running kernel, and said kernel # does not exist in the new release, add "kernel/generic" to the # list of components. upgrade_guess_new_kernel INDEX-ALL || return 1 # Filter INDEX-ALL to contain only the components we want and without # anything marked as "Ignore". fetch_filter_metadata INDEX-ALL || return 1 # Convert INDEX-OLD (last release) and INDEX-ALL (new release) into # INDEX-OLD and INDEX-NEW files (in the sense of normal upgrades). upgrade_oldall_to_oldnew INDEX-OLD INDEX-ALL INDEX-NEW # Translate /boot/${KERNCONF} or /boot/${NKERNCONF} into ${KERNELDIR} fetch_filter_kernel_names INDEX-NEW ${NKERNCONF} fetch_filter_kernel_names INDEX-OLD ${KERNCONF} # For all paths appearing in INDEX-OLD or INDEX-NEW, inspect the # system and generate an INDEX-PRESENT file. fetch_inspect_system INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 # Based on ${MERGECHANGES}, generate a file tomerge-old with the # paths and hashes of old versions of files to merge. fetch_filter_mergechanges INDEX-OLD INDEX-PRESENT tomerge-old # Based on ${UPDATEIFUNMODIFIED}, remove lines from INDEX-* which # correspond to lines in INDEX-PRESENT with hashes not appearing # in INDEX-OLD or INDEX-NEW. Also remove lines where the entry in # INDEX-PRESENT has type - and there isn't a corresponding entry in # INDEX-OLD with type -. fetch_filter_unmodified_notpresent \ INDEX-OLD INDEX-PRESENT INDEX-NEW tomerge-old # For each entry in INDEX-PRESENT of type -, remove any corresponding # entry from INDEX-NEW if ${ALLOWADD} != "yes". Remove all entries # of type - from INDEX-PRESENT. fetch_filter_allowadd INDEX-PRESENT INDEX-NEW # If ${ALLOWDELETE} != "yes", then remove any entries from # INDEX-PRESENT which don't correspond to entries in INDEX-NEW. fetch_filter_allowdelete INDEX-PRESENT INDEX-NEW # If ${KEEPMODIFIEDMETADATA} == "yes", then for each entry in # INDEX-PRESENT with metadata not matching any entry in INDEX-OLD, # replace the corresponding line of INDEX-NEW with one having the # same metadata as the entry in INDEX-PRESENT. fetch_filter_modified_metadata INDEX-OLD INDEX-PRESENT INDEX-NEW # Remove lines from INDEX-PRESENT and INDEX-NEW which are identical; # no need to update a file if it isn't changing. fetch_filter_uptodate INDEX-PRESENT INDEX-NEW # Fetch "clean" files from the old release for merging changes. fetch_files_premerge tomerge-old # Prepare to fetch files: Generate a list of the files we need, # copy the unmodified files we have into /files/, and generate # a list of patches to download. fetch_files_prepare INDEX-OLD INDEX-PRESENT INDEX-NEW || return 1 # Fetch patches from to-${RELNUM}/${ARCH}/bp/ PATCHDIR=to-${RELNUM}/${ARCH}/bp fetch_files || return 1 # Merge configuration file changes. upgrade_merge tomerge-old INDEX-PRESENT INDEX-NEW || return 1 # Create and populate install manifest directory; and report what # updates are available. fetch_create_manifest || return 1 # Leave a note behind to tell the "install" command that the kernel # needs to be installed before the world. touch ${BDHASH}-install/kernelfirst # Remind the user that they need to run "freebsd-update install" # to install the downloaded bits, in case they didn't RTFM. echo "To install the downloaded upgrades, run \"$0 install\"." } # Make sure that all the file hashes mentioned in $@ have corresponding # gzipped files stored in /files/. install_verify () { # Generate a list of hashes cat $@ | cut -f 2,7 -d '|' | grep -E '^f' | cut -f 2 -d '|' | sort -u > filelist # Make sure all the hashes exist while read HASH; do if ! [ -f files/${HASH}.gz ]; then echo -n "Update files missing -- " echo "this should never happen." echo "Re-run '$0 fetch'." return 1 fi done < filelist # Clean up rm filelist } # Remove the system immutable flag from files install_unschg () { # Generate file list cat $@ | cut -f 1 -d '|' > filelist # Remove flags while read F; do if ! [ -e ${BASEDIR}/${F} ]; then continue else echo ${BASEDIR}/${F} fi done < filelist | xargs chflags noschg || return 1 # Clean up rm filelist } # Decide which directory name to use for kernel backups. backup_kernel_finddir () { CNT=0 while true ; do # Pathname does not exist, so it is OK use that name # for backup directory. if [ ! -e $BASEDIR/$BACKUPKERNELDIR ]; then return 0 fi # If directory do exist, we only use if it has our # marker file. if [ -d $BASEDIR/$BACKUPKERNELDIR -a \ -e $BASEDIR/$BACKUPKERNELDIR/.freebsd-update ]; then return 0 fi # We could not use current directory name, so add counter to # the end and try again. CNT=$((CNT + 1)) if [ $CNT -gt 9 ]; then echo "Could not find valid backup dir ($BASEDIR/$BACKUPKERNELDIR)" exit 1 fi BACKUPKERNELDIR="`echo $BACKUPKERNELDIR | sed -Ee 's/[0-9]\$//'`" BACKUPKERNELDIR="${BACKUPKERNELDIR}${CNT}" done } # Backup the current kernel using hardlinks, if not disabled by user. # Since we delete all files in the directory used for previous backups # we create a marker file called ".freebsd-update" in the directory so # we can determine on the next run that the directory was created by # freebsd-update and we then do not accidentally remove user files in # the unlikely case that the user has created a directory with a # conflicting name. backup_kernel () { # Only make kernel backup is so configured. if [ $BACKUPKERNEL != yes ]; then return 0 fi # Decide which directory name to use for kernel backups. backup_kernel_finddir # Remove old kernel backup files. If $BACKUPKERNELDIR was # "not ours", backup_kernel_finddir would have exited, so # deleting the directory content is as safe as we can make it. if [ -d $BASEDIR/$BACKUPKERNELDIR ]; then rm -fr $BASEDIR/$BACKUPKERNELDIR fi # Create directories for backup. mkdir -p $BASEDIR/$BACKUPKERNELDIR mtree -cdn -p "${BASEDIR}/${KERNELDIR}" | \ mtree -Ue -p "${BASEDIR}/${BACKUPKERNELDIR}" > /dev/null # Mark the directory as having been created by freebsd-update. touch $BASEDIR/$BACKUPKERNELDIR/.freebsd-update if [ $? -ne 0 ]; then echo "Could not create kernel backup directory" exit 1 fi # Disable pathname expansion to be sure *.symbols is not # expanded. set -f # Use find to ignore symbol files, unless disabled by user. if [ $BACKUPKERNELSYMBOLFILES = yes ]; then FINDFILTER="" else FINDFILTER="-a ! -name *.debug -a ! -name *.symbols" fi # Backup all the kernel files using hardlinks. (cd ${BASEDIR}/${KERNELDIR} && find . -type f $FINDFILTER -exec \ cp -pl '{}' ${BASEDIR}/${BACKUPKERNELDIR}/'{}' \;) # Re-enable patchname expansion. set +f } # Install new files install_from_index () { # First pass: Do everything apart from setting file flags. We # can't set flags yet, because schg inhibits hard linking. sort -k 1,1 -t '|' $1 | tr '|' ' ' | while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do case ${TYPE} in d) # Create a directory install -d -o ${OWNER} -g ${GROUP} \ -m ${PERM} ${BASEDIR}/${FPATH} ;; f) if [ -z "${LINK}" ]; then # Create a file, without setting flags. gunzip < files/${HASH}.gz > ${HASH} install -S -o ${OWNER} -g ${GROUP} \ -m ${PERM} ${HASH} ${BASEDIR}/${FPATH} rm ${HASH} else # Create a hard link. ln -f ${BASEDIR}/${LINK} ${BASEDIR}/${FPATH} fi ;; L) # Create a symlink ln -sfh ${HASH} ${BASEDIR}/${FPATH} ;; esac done # Perform a second pass, adding file flags. tr '|' ' ' < $1 | while read FPATH TYPE OWNER GROUP PERM FLAGS HASH LINK; do if [ ${TYPE} = "f" ] && ! [ ${FLAGS} = "0" ]; then chflags ${FLAGS} ${BASEDIR}/${FPATH} fi done } # Remove files which we want to delete install_delete () { # Generate list of new files cut -f 1 -d '|' < $2 | sort > newfiles # Generate subindex of old files we want to nuke sort -k 1,1 -t '|' $1 | join -t '|' -v 1 - newfiles | sort -r -k 1,1 -t '|' | cut -f 1,2 -d '|' | tr '|' ' ' > killfiles # Remove the offending bits while read FPATH TYPE; do case ${TYPE} in d) rmdir ${BASEDIR}/${FPATH} ;; f) rm ${BASEDIR}/${FPATH} ;; L) rm ${BASEDIR}/${FPATH} ;; esac done < killfiles # Clean up rm newfiles killfiles } # Install new files, delete old files, and update linker.hints install_files () { # If we haven't already dealt with the kernel, deal with it. if ! [ -f $1/kerneldone ]; then grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW # Backup current kernel before installing a new one backup_kernel || return 1 # Install new files install_from_index INDEX-NEW || return 1 # Remove files which need to be deleted install_delete INDEX-OLD INDEX-NEW || return 1 # Update linker.hints if necessary if [ -s INDEX-OLD -o -s INDEX-NEW ]; then kldxref -R ${BASEDIR}/boot/ 2>/dev/null fi # We've finished updating the kernel. touch $1/kerneldone # Do we need to ask for a reboot now? if [ -f $1/kernelfirst ] && [ -s INDEX-OLD -o -s INDEX-NEW ]; then cat <<-EOF Kernel updates have been installed. Please reboot and run "$0 install" again to finish installing updates. EOF exit 0 fi fi # If we haven't already dealt with the world, deal with it. if ! [ -f $1/worlddone ]; then # Create any necessary directories first grep -vE '^/boot/' $1/INDEX-NEW | grep -E '^[^|]+\|d\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 # Install new runtime linker grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | grep -E '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 # Install new shared libraries next grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 # Deal with everything else grep -vE '^/boot/' $1/INDEX-OLD | grep -vE '^[^|]+\|d\|' | grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | grep -vE '^/libexec/ld-elf[^|]*\.so\.[0-9]+\|' | grep -vE '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-NEW || return 1 install_delete INDEX-OLD INDEX-NEW || return 1 # Rebuild /etc/spwd.db and /etc/pwd.db if necessary. if [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/spwd.db ] || [ ${BASEDIR}/etc/master.passwd -nt ${BASEDIR}/etc/pwd.db ]; then pwd_mkdb -d ${BASEDIR}/etc ${BASEDIR}/etc/master.passwd fi # Rebuild /etc/login.conf.db if necessary. if [ ${BASEDIR}/etc/login.conf -nt ${BASEDIR}/etc/login.conf.db ]; then cap_mkdb ${BASEDIR}/etc/login.conf fi # We've finished installing the world and deleting old files # which are not shared libraries. touch $1/worlddone # Do we need to ask the user to portupgrade now? grep -vE '^/boot/' $1/INDEX-NEW | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' | cut -f 1 -d '|' | sort > newfiles if grep -vE '^/boot/' $1/INDEX-OLD | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' | cut -f 1 -d '|' | sort | join -v 1 - newfiles | grep -q .; then cat <<-EOF Completing this upgrade requires removing old shared object files. Please rebuild all installed 3rd party software (e.g., programs installed from the ports tree) and then run "$0 install" again to finish installing updates. EOF rm newfiles exit 0 fi rm newfiles fi # Remove old shared libraries grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '^[^|]+\|d\|' | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-NEW grep -vE '^/boot/' $1/INDEX-OLD | grep -vE '^[^|]+\|d\|' | grep -E '^[^|]*/lib/[^|]*\.so\.[0-9]+\|' > INDEX-OLD install_delete INDEX-OLD INDEX-NEW || return 1 # Remove old directories grep -vE '^/boot/' $1/INDEX-NEW | grep -E '^[^|]+\|d\|' > INDEX-NEW grep -vE '^/boot/' $1/INDEX-OLD | grep -E '^[^|]+\|d\|' > INDEX-OLD install_delete INDEX-OLD INDEX-NEW || return 1 # Remove temporary files rm INDEX-OLD INDEX-NEW } # Rearrange bits to allow the installed updates to be rolled back install_setup_rollback () { # Remove the "reboot after installing kernel", "kernel updated", and # "finished installing the world" flags if present -- they are # irrelevant when rolling back updates. if [ -f ${BDHASH}-install/kernelfirst ]; then rm ${BDHASH}-install/kernelfirst rm ${BDHASH}-install/kerneldone fi if [ -f ${BDHASH}-install/worlddone ]; then rm ${BDHASH}-install/worlddone fi if [ -L ${BDHASH}-rollback ]; then mv ${BDHASH}-rollback ${BDHASH}-install/rollback fi mv ${BDHASH}-install ${BDHASH}-rollback } # Actually install updates install_run () { echo -n "Installing updates..." # Make sure we have all the files we should have install_verify ${BDHASH}-install/INDEX-OLD \ ${BDHASH}-install/INDEX-NEW || return 1 # Remove system immutable flag from files install_unschg ${BDHASH}-install/INDEX-OLD \ ${BDHASH}-install/INDEX-NEW || return 1 # Install new files, delete old files, and update linker.hints install_files ${BDHASH}-install || return 1 # Rearrange bits to allow the installed updates to be rolled back install_setup_rollback echo " done." } # Rearrange bits to allow the previous set of updates to be rolled back next. rollback_setup_rollback () { if [ -L ${BDHASH}-rollback/rollback ]; then mv ${BDHASH}-rollback/rollback rollback-tmp rm -r ${BDHASH}-rollback/ rm ${BDHASH}-rollback mv rollback-tmp ${BDHASH}-rollback else rm -r ${BDHASH}-rollback/ rm ${BDHASH}-rollback fi } # Install old files, delete new files, and update linker.hints rollback_files () { # Install old shared library files which don't have the same path as # a new shared library file. grep -vE '^/boot/' $1/INDEX-NEW | grep -E '/lib/.*\.so\.[0-9]+\|' | cut -f 1 -d '|' | sort > INDEX-NEW.libs.flist grep -vE '^/boot/' $1/INDEX-OLD | grep -E '/lib/.*\.so\.[0-9]+\|' | sort -k 1,1 -t '|' - | join -t '|' -v 1 - INDEX-NEW.libs.flist > INDEX-OLD install_from_index INDEX-OLD || return 1 # Deal with files which are neither kernel nor shared library grep -vE '^/boot/' $1/INDEX-OLD | grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD grep -vE '^/boot/' $1/INDEX-NEW | grep -vE '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW install_from_index INDEX-OLD || return 1 install_delete INDEX-NEW INDEX-OLD || return 1 # Install any old shared library files which we didn't install above. grep -vE '^/boot/' $1/INDEX-OLD | grep -E '/lib/.*\.so\.[0-9]+\|' | sort -k 1,1 -t '|' - | join -t '|' - INDEX-NEW.libs.flist > INDEX-OLD install_from_index INDEX-OLD || return 1 # Delete unneeded shared library files grep -vE '^/boot/' $1/INDEX-OLD | grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-OLD grep -vE '^/boot/' $1/INDEX-NEW | grep -E '/lib/.*\.so\.[0-9]+\|' > INDEX-NEW install_delete INDEX-NEW INDEX-OLD || return 1 # Deal with kernel files grep -E '^/boot/' $1/INDEX-OLD > INDEX-OLD grep -E '^/boot/' $1/INDEX-NEW > INDEX-NEW install_from_index INDEX-OLD || return 1 install_delete INDEX-NEW INDEX-OLD || return 1 if [ -s INDEX-OLD -o -s INDEX-NEW ]; then kldxref -R /boot/ 2>/dev/null fi # Remove temporary files rm INDEX-OLD INDEX-NEW INDEX-NEW.libs.flist } # Actually rollback updates rollback_run () { echo -n "Uninstalling updates..." # If there are updates waiting to be installed, remove them; we # want the user to re-run 'fetch' after rolling back updates. if [ -L ${BDHASH}-install ]; then rm -r ${BDHASH}-install/ rm ${BDHASH}-install fi # Make sure we have all the files we should have install_verify ${BDHASH}-rollback/INDEX-NEW \ ${BDHASH}-rollback/INDEX-OLD || return 1 # Remove system immutable flag from files install_unschg ${BDHASH}-rollback/INDEX-NEW \ ${BDHASH}-rollback/INDEX-OLD || return 1 # Install old files, delete new files, and update linker.hints rollback_files ${BDHASH}-rollback || return 1 # Remove the rollback directory and the symlink pointing to it; and # rearrange bits to allow the previous set of updates to be rolled # back next. rollback_setup_rollback echo " done." } # Compare INDEX-ALL and INDEX-PRESENT and print warnings about differences. IDS_compare () { # Get all the lines which mismatch in something other than file # flags. We ignore file flags because sysinstall doesn't seem to # set them when it installs FreeBSD; warning about these adds a # very large amount of noise. cut -f 1-5,7-8 -d '|' $1 > $1.noflags sort -k 1,1 -t '|' $1.noflags > $1.sorted cut -f 1-5,7-8 -d '|' $2 | comm -13 $1.noflags - | fgrep -v '|-|||||' | sort -k 1,1 -t '|' | join -t '|' $1.sorted - > INDEX-NOTMATCHING # Ignore files which match IDSIGNOREPATHS. for X in ${IDSIGNOREPATHS}; do grep -E "^${X}" INDEX-NOTMATCHING done | sort -u | comm -13 - INDEX-NOTMATCHING > INDEX-NOTMATCHING.tmp mv INDEX-NOTMATCHING.tmp INDEX-NOTMATCHING # Go through the lines and print warnings. local IFS='|' while read FPATH TYPE OWNER GROUP PERM HASH LINK P_TYPE P_OWNER P_GROUP P_PERM P_HASH P_LINK; do # Warn about different object types. if ! [ "${TYPE}" = "${P_TYPE}" ]; then echo -n "${FPATH} is a " case "${P_TYPE}" in f) echo -n "regular file, " ;; d) echo -n "directory, " ;; L) echo -n "symlink, " ;; esac echo -n "but should be a " case "${TYPE}" in f) echo -n "regular file." ;; d) echo -n "directory." ;; L) echo -n "symlink." ;; esac echo # Skip other tests, since they don't make sense if # we're comparing different object types. continue fi # Warn about different owners. if ! [ "${OWNER}" = "${P_OWNER}" ]; then echo -n "${FPATH} is owned by user id ${P_OWNER}, " echo "but should be owned by user id ${OWNER}." fi # Warn about different groups. if ! [ "${GROUP}" = "${P_GROUP}" ]; then echo -n "${FPATH} is owned by group id ${P_GROUP}, " echo "but should be owned by group id ${GROUP}." fi # Warn about different permissions. We do not warn about # different permissions on symlinks, since some archivers # don't extract symlink permissions correctly and they are # ignored anyway. if ! [ "${PERM}" = "${P_PERM}" ] && ! [ "${TYPE}" = "L" ]; then echo -n "${FPATH} has ${P_PERM} permissions, " echo "but should have ${PERM} permissions." fi # Warn about different file hashes / symlink destinations. if ! [ "${HASH}" = "${P_HASH}" ]; then if [ "${TYPE}" = "L" ]; then echo -n "${FPATH} is a symlink to ${P_HASH}, " echo "but should be a symlink to ${HASH}." fi if [ "${TYPE}" = "f" ]; then echo -n "${FPATH} has SHA256 hash ${P_HASH}, " echo "but should have SHA256 hash ${HASH}." fi fi # We don't warn about different hard links, since some # some archivers break hard links, and as long as the # underlying data is correct they really don't matter. done < INDEX-NOTMATCHING # Clean up rm $1 $1.noflags $1.sorted $2 INDEX-NOTMATCHING } # Do the work involved in comparing the system to a "known good" index IDS_run () { workdir_init || return 1 # Prepare the mirror list. fetch_pick_server_init && fetch_pick_server # Try to fetch the public key until we run out of servers. while ! fetch_key; do fetch_pick_server || return 1 done # Try to fetch the metadata index signature ("tag") until we run # out of available servers; and sanity check the downloaded tag. while ! fetch_tag; do fetch_pick_server || return 1 done fetch_tagsanity || return 1 # Fetch INDEX-OLD and INDEX-ALL. fetch_metadata INDEX-OLD INDEX-ALL || return 1 # Generate filtered INDEX-OLD and INDEX-ALL files containing only # the components we want and without anything marked as "Ignore". fetch_filter_metadata INDEX-OLD || return 1 fetch_filter_metadata INDEX-ALL || return 1 # Merge the INDEX-OLD and INDEX-ALL files into INDEX-ALL. sort INDEX-OLD INDEX-ALL > INDEX-ALL.tmp mv INDEX-ALL.tmp INDEX-ALL rm INDEX-OLD # Translate /boot/${KERNCONF} to ${KERNELDIR} fetch_filter_kernel_names INDEX-ALL ${KERNCONF} # Inspect the system and generate an INDEX-PRESENT file. fetch_inspect_system INDEX-ALL INDEX-PRESENT /dev/null || return 1 # Compare INDEX-ALL and INDEX-PRESENT and print warnings about any # differences. IDS_compare INDEX-ALL INDEX-PRESENT } #### Main functions -- call parameter-handling and core functions # Using the command line, configuration file, and defaults, # set all the parameters which are needed later. get_params () { init_params parse_cmdline $@ parse_conffile default_params } # Fetch command. Make sure that we're being called # interactively, then run fetch_check_params and fetch_run cmd_fetch () { if [ ! -t 0 -a $NOTTYOK -eq 0 ]; then echo -n "`basename $0` fetch should not " echo "be run non-interactively." echo "Run `basename $0` cron instead." exit 1 fi fetch_check_params fetch_run || exit 1 ISFETCHED=1 } # Cron command. Make sure the parameters are sensible; wait # rand(3600) seconds; then fetch updates. While fetching updates, # send output to a temporary file; only print that file if the # fetching failed. cmd_cron () { fetch_check_params sleep `jot -r 1 0 3600` TMPFILE=`mktemp /tmp/freebsd-update.XXXXXX` || exit 1 if ! fetch_run >> ${TMPFILE} || ! grep -q "No updates needed" ${TMPFILE} || [ ${VERBOSELEVEL} = "debug" ]; then mail -s "`hostname` security updates" ${MAILTO} < ${TMPFILE} fi rm ${TMPFILE} } # Fetch files for upgrading to a new release. cmd_upgrade () { upgrade_check_params upgrade_run || exit 1 } # Install downloaded updates. cmd_install () { install_check_params install_run || exit 1 } # Rollback most recently installed updates. cmd_rollback () { rollback_check_params rollback_run || exit 1 } # Compare system against a "known good" index. cmd_IDS () { IDS_check_params IDS_run || exit 1 } #### Entry point # Make sure we find utilities from the base system export PATH=/sbin:/bin:/usr/sbin:/usr/bin:${PATH} # Set a pager if the user doesn't if [ -z "$PAGER" ]; then - PAGER=/usr/bin/more + PAGER=/usr/bin/less fi # Set LC_ALL in order to avoid problems with character ranges like [A-Z]. export LC_ALL=C get_params $@ for COMMAND in ${COMMANDS}; do cmd_${COMMAND} done Index: head/usr.sbin/mergemaster/mergemaster.8 =================================================================== --- head/usr.sbin/mergemaster/mergemaster.8 (revision 337496) +++ head/usr.sbin/mergemaster/mergemaster.8 (revision 337497) @@ -1,476 +1,476 @@ .\" Copyright (c) 1998-2011 Douglas Barton .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must 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. .\" .\" $FreeBSD$ .\" -.Dd March 6, 2017 +.Dd August 8, 2018 .Dt MERGEMASTER 8 .Os .Sh NAME .Nm mergemaster .Nd merge configuration files, et al during an upgrade .Sh SYNOPSIS .Nm .Op Fl scrvhpCP .Op Fl a|iFU .Op Fl -run-updates=[always|never] .Op Fl m Ar /path/to/sources .Op Fl t Ar /path/to/temp/root .Op Fl d .Op Fl u Ar N .Op Fl w Ar N .Op Fl A Ar Target architecture .Op Fl D Ar /destdir/path .Sh DESCRIPTION The .Nm utility is a Bourne shell script which is designed to aid you in updating the various configuration and other files associated with .Fx . It is .Sy HIGHLY recommended that you back up your .Pa /etc directory before beginning this process. .Pp The script uses .Pa /usr/src/Makefile to build a temporary root environment from .Pa / down, populating that environment with the various files. You can specify a different source directory with the .Fl m command line option, or specify the destination directory with the .Fl D option. It then compares each file in that environment to its installed counterpart. When the script finds a change in the new file, or there is no installed version of the new file it gives you four options to deal with it. You can install the new file as is, delete the new file, merge the old and new files (as appropriate) using .Xr sdiff 1 or leave the file in the temporary root environment to merge by hand later. .Pp By default it creates the temporary root in .Pa /var/tmp/temproot and compares the Version Control System (VCS) Id strings ($FreeBSD) for files that have them, deleting the temporary file if the strings match. If there is no Id string, or if the strings are different it compares the files themselves. You can also specify that the script ignore the Id strings and compare every file with the .Fl s option. Using the .Fl F option .Nm will install the new file for you if they differ only by VCS strings. .Pp The merge menu option is designed to let you easily combine your customizations from the old version of a file into the new one. While you can use the merge function to incorporate changes from files that you have not customized, it is not recommended. .Pp The .Nm utility checks your umask and issues a warning for anything other than 022. While it is not mandatory to grant world read permissions for most configuration files, you may run into problems without them. If you choose a umask other than 022 and experience trouble later this could be the cause. .Pa /etc/master.passwd is treated as a special case. If you choose to install this file or a merged version of it the file permissions are always 600 (rw-------) for security reasons. After installing an updated version of this file you should probably run .Xr pwd_mkdb 8 with the .Fl p option to rebuild your password databases and recreate .Pa /etc/passwd . .Pp The script uses the owner and group ids that the files are created with by .Pa /usr/src/etc/Makefile , and file permissions as specified by the umask. Unified diffs are used by default to display any differences unless you choose context diffs. .Pp The .Nm utility will source scripts that you specify right before it starts the comparison, and after it is done running. The easiest way to handle this is to place the path to the script(s) in the appropriate variables in your .Pa .mergemasterrc file. The script sourced before comparison is named in .Ev MM_PRE_COMPARE_SCRIPT , and the one sourced after the script is done is .Ev MM_EXIT_SCRIPT . This is the recommended way to specify local modifications, or files that you want to give special handling to. This includes files that you want to be deleted without being compared. Because the named scripts are sourced from within .Nm , all of the script's variables are available for use in your custom script. You can also use .Pa /etc/mergemaster.rc which will be read before .Pa .mergemasterrc . Options specified on the command line are updated last, and therefore can override both files. .Pp When the comparison is done if there are any files remaining in the temproot directory they will be listed, and if the .Fl a option is not in use the user will be given the option of deleting the temproot directory. If there are no files remaining in the temproot directory it will be deleted. .Pp The options are as follows: .Bl -tag -width Fl .It Fl s Perform a strict comparison, diffing every pair of files. This comparison is performed line by line, without regard to VCS Ids. .It Fl c Use context diffs instead of unified diffs. .It Fl r Re-run .Nm on a previously cleaned directory, skipping the creation of the temporary root environment. This option is compatible with all other options. .It Fl v Be more verbose about the process. You should probably use this option the first time you run .Nm . This option also gives you a list of files that exist only in the installed version of .Pa /etc . .It Fl a Run automatically. This option will leave all the files that differ from the installed versions in the temporary directory to be dealt with by hand. If the .Pa temproot directory exists, it creates a new one in a previously non-existent directory. This option unsets the verbose flag, and is not compatible with .Fl i , .Fl F , or .Fl U . Setting .Fl a makes .Fl w superfluous. .It Fl h Display usage and help information. .It Fl i Automatically install any files that do not exist in the destination directory. .It Fl p Pre-buildworld mode. Compares only files known to be essential to the success of {build|install}world, i.e., .Pa /etc/group and .Pa /etc/master.passwd . .It Fl F If the files differ only by VCS Id ($FreeBSD) install the new file. .It Fl C After a standard .Nm run, compares your rc.conf[.local] options to the defaults. .It Fl P Preserve files that you replace in .Pa /var/tmp/mergemaster/preserved-files- , or another directory you specify in your .Nm rc file. .It Fl U Attempt to auto upgrade files that have not been user modified. This option can be dangerous when there are critical changes in the new versions that affect your running system. .It Fl -run-updates=[always|never] Specify always or never to run newaliases, pwd_mkdb, etc. at the end of the comparison run. If this option is omitted the default is to prompt the user for each update as necessary. .It Fl m Ar /path/to/sources Specify the path to the directory where you want to do the .Xr make 1 . (In other words, where your sources are, but -s was already taken.) In older versions of .Nm the path to .Pa src/etc was required. .Nm will convert the path if this older method is used. .It Fl t Ar /path/to/temp/root Create the temporary root environment in .Pa /path/to/temp/root instead of the default .Pa /var/tmp/temproot . .It Fl d Add the date and time to the name of the temporary root directory. If .Fl t is specified, this option must follow it if you want the date added too. .It Fl u Ar N Specify a numeric umask. The default is 022. .It Fl w Ar N Supply an alternate screen width to the .Xr sdiff 1 command in numbers of columns. The default is 80. .It Fl A Ar Target architecture Specify an alternative .Ev TARGET_ARCH architecture name. .It Fl D Ar /path Specify the destination directory for the installed files. .El .Sh ENVIRONMENT The .Nm utility uses the .Ev PAGER environment variable if set. Otherwise it uses -.Xr more 1 . +.Xr less 1 . If .Ev PAGER specifies a program outside its limited .Ev PATH without specifying the full path, .Nm prompts you with options on how to proceed. The .Ev MM_PRE_COMPARE_SCRIPT and .Ev MM_EXIT_SCRIPT variables are used as described above. Other variables that are used by the script internally can be specified in .Pa .mergemasterrc as described in more detail below. .Sh FILES .Bl -tag -width $HOME/.mergemasterrc -compact .It Pa /etc/mergemaster.rc .It Pa $HOME/.mergemasterrc .El .Pp The .Nm utility will .Ic .\& (source) these files if they exist. Command line options will override rc file options. .Pa $HOME/.mergemasterrc overrides .Pa /etc/mergemaster.rc . Here is an example with all values commented out: .Bd -literal # These are options for mergemaster, with their default values listed # The following options have command line overrides # # The target architecture (-A, unset by default) #ARCHSTRING='TARGET_ARCH=' # # Sourcedir is the directory to do the 'make' in (-m) #SOURCEDIR='/usr/src' # # Directory to install the temporary root environment into (-t) #TEMPROOT='/var/tmp/temproot' # # Specify the destination directory for the installed files (-D) #DESTDIR= # # Strict comparison skips the VCS Id test and compares every file (-s) #STRICT=no # # Type of diff, such as unified, context, etc. (-c) #DIFF_FLAG='-u' # # Install the new file if it differs only by VCS Id ($FreeBSD, -F) #FREEBSD_ID= # # Verbose mode includes more details and additional checks (-v) #VERBOSE= # # Automatically install files that do not exist on the system already (-i) #AUTO_INSTALL= # # Automatically upgrade files that have not been user modified (-U) # ***DANGEROUS*** #AUTO_UPGRADE= # # Either always or never run newaliases, pwd_mkdb at the end (--run-updates) #RUN_UPDATES= # # Compare /etc/rc.conf[.local] to /etc/defaults/rc.conf (-C) #COMP_CONFS= # # Preserve files that you replace (-P) #PRESERVE_FILES= #PRESERVE_FILES_DIR=/var/tmp/mergemaster/preserved-files-`date +%y%m%d-%H%M%S` # # The umask for mergemaster to compare the default file's modes to (-u) #NEW_UMASK=022 # # The following options have no command line overrides # # Files to always avoid comparing #IGNORE_FILES='/etc/motd /etc/printcap foo bar' # # Additional options for diff. This will get unset when using -s. #DIFF_OPTIONS='-Bb' # Ignore changes in whitespace # # Location to store the list of mtree values for AUTO_UPGRADE purposes #MTREEDB='/var/db' # # For those who just cannot stand including the full path to PAGER #DONT_CHECK_PAGER= # # If you set 'yes' above, make sure to include the PATH to your pager #PATH=/bin:/usr/bin:/usr/sbin # # Delete stale files in /etc/rc.d without prompting #DELETE_STALE_RC_FILES= # # Specify the path to scripts to run before the comparison starts, # and/or after the script has finished its work #MM_PRE_COMPARE_SCRIPT= #MM_EXIT_SCRIPT= .Ed .Sh EXIT STATUS Exit status is 0 on successful completion, or if the user bails out manually at some point during execution. .Pp Exit status is 1 if it fails for one of the following reasons: .Pp Invalid command line option .Pp Failure to create the temporary root environment .Pp Failure to populate the temporary root .Pp Presence of the 'nodev' option in .Pa /etc/fstab .Pp Failure to install a file .Sh EXAMPLES Typically all you will need to do is type .Nm at the prompt and the script will do all the work for you. .Pp To use context diffs and have .Nm explain more things as it goes along, use: .Pp .Dl # mergemaster -cv .Pp To specify that .Nm put the temporary root environment in .Pa /usr/tmp/root , use: .Pp .Dl # mergemaster -t /usr/tmp/root .Pp To specify a 110 column screen with a strict comparison, use: .Pp .Dl # mergemaster -sw 110 .Sh SEE ALSO .Xr diff 1 , .Xr make 1 , -.Xr more 1 , +.Xr less 1 , .Xr sdiff 1 , .Xr pwd_mkdb 8 .Pp .Pa /usr/src/etc/Makefile .Rs .%U https://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/makeworld.html .%T The Cutting Edge (using make world) .%A Nik Clayton .Re .Sh HISTORY The .Nm utility was first publicly available on one of my web pages in a much simpler form under the name .Pa comproot on 13 March 1998. The idea for creating the temporary root environment comes from Nik Clayton's make world tutorial which is referenced above. .Sh AUTHORS This manual page and the script itself were written by .An Douglas Barton Aq Mt dougb@FreeBSD.org . Index: head/usr.sbin/mergemaster/mergemaster.sh =================================================================== --- head/usr.sbin/mergemaster/mergemaster.sh (revision 337496) +++ head/usr.sbin/mergemaster/mergemaster.sh (revision 337497) @@ -1,1414 +1,1414 @@ #!/bin/sh # mergemaster # Compare files created by /usr/src/etc/Makefile (or the directory # the user specifies) with the currently installed copies. # Copyright (c) 1998-2012 Douglas Barton, All rights reserved # Please see detailed copyright below # $FreeBSD$ PATH=/bin:/usr/bin:/usr/sbin display_usage () { VERSION_NUMBER=`grep "[$]FreeBSD:" $0 | cut -d ' ' -f 4` echo "mergemaster version ${VERSION_NUMBER}" echo 'Usage: mergemaster [-scrvhpCP] [-a|[-iFU]] [--run-updates=always|never]' echo ' [-m /path] [-t /path] [-d] [-u N] [-w N] [-A arch] [-D /path]' echo "Options:" echo " -s Strict comparison (diff every pair of files)" echo " -c Use context diff instead of unified diff" echo " -r Re-run on a previously cleaned directory (skip temproot creation)" echo " -v Be more verbose about the process, include additional checks" echo " -a Leave all files that differ to merge by hand" echo " -h Display more complete help" echo ' -i Automatically install files that do not exist in destination directory' echo ' -p Pre-buildworld mode, only compares crucial files' echo ' -F Install files that differ only by revision control Id ($FreeBSD)' echo ' -C Compare local rc.conf variables to the defaults' echo ' -P Preserve files that are overwritten' echo " -U Attempt to auto upgrade files that have not been user modified" echo ' ***DANGEROUS***' echo ' --run-updates= Specify always or never to run newalises, pwd_mkdb, etc.' echo '' echo " -m /path/directory Specify location of source to do the make in" echo " -t /path/directory Specify temp root directory" echo " -d Add date and time to directory name (e.g., /var/tmp/temproot.`date +%m%d.%H.%M`)" echo " -u N Specify a numeric umask" echo " -w N Specify a screen width in columns to sdiff" echo " -A architecture Alternative architecture name to pass to make" echo ' -D /path/directory Specify the destination directory to install files to' echo '' } display_help () { echo "* To specify a directory other than /var/tmp/temproot for the" echo " temporary root environment, use -t /path/to/temp/root" echo "* The -w option takes a number as an argument for the column width" echo " of the screen. The default is 80." echo '* The -a option causes mergemaster to run without prompting.' } # Loop allowing the user to use sdiff to merge files and display the merged # file. merge_loop () { case "${VERBOSE}" in '') ;; *) echo " *** Type h at the sdiff prompt (%) to get usage help" ;; esac echo '' MERGE_AGAIN=yes while [ "${MERGE_AGAIN}" = "yes" ]; do # Prime file.merged so we don't blat the owner/group id's cp -p "${COMPFILE}" "${COMPFILE}.merged" sdiff -o "${COMPFILE}.merged" --text --suppress-common-lines \ --width=${SCREEN_WIDTH:-80} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" INSTALL_MERGED=V while [ "${INSTALL_MERGED}" = "v" -o "${INSTALL_MERGED}" = "V" ]; do echo '' echo " Use 'i' to install merged file" echo " Use 'r' to re-do the merge" echo " Use 'v' to view the merged file" echo " Default is to leave the temporary file to deal with by hand" echo '' echo -n " *** How should I deal with the merged file? [Leave it for later] " read INSTALL_MERGED case "${INSTALL_MERGED}" in [iI]) mv "${COMPFILE}.merged" "${COMPFILE}" echo '' if mm_install "${COMPFILE}"; then echo " *** Merged version of ${COMPFILE} installed successfully" else echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand later" fi unset MERGE_AGAIN ;; [rR]) rm "${COMPFILE}.merged" ;; [vV]) ${PAGER} "${COMPFILE}.merged" ;; '') echo " *** ${COMPFILE} will remain for your consideration" unset MERGE_AGAIN ;; *) echo "invalid choice: ${INSTALL_MERGED}" INSTALL_MERGED=V ;; esac done done } # Loop showing user differences between files, allow merge, skip or install # options diff_loop () { HANDLE_COMPFILE=v while [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" -o \ "${HANDLE_COMPFILE}" = "NOT V" ]; do if [ -f "${DESTDIR}${COMPFILE#.}" -a -f "${COMPFILE}" ]; then if [ -n "${AUTO_UPGRADE}" -a -n "${CHANGED}" ]; then case "${CHANGED}" in *:${DESTDIR}${COMPFILE#.}:*) ;; # File has been modified *) echo '' echo " *** ${COMPFILE} has not been user modified." echo '' if mm_install "${COMPFILE}"; then echo " *** ${COMPFILE} upgraded successfully" echo '' # Make the list print one file per line AUTO_UPGRADED_FILES="${AUTO_UPGRADED_FILES} ${DESTDIR}${COMPFILE#.} " else echo " *** Problem upgrading ${COMPFILE}, it will remain to merge by hand" fi return ;; esac fi if [ "${HANDLE_COMPFILE}" = "v" -o "${HANDLE_COMPFILE}" = "V" ]; then echo '' echo ' ====================================================================== ' echo '' ( echo " *** Displaying differences between ${COMPFILE} and installed version:" echo '' diff ${DIFF_FLAG} ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" ) | ${PAGER} echo '' fi else echo '' echo " *** There is no installed version of ${COMPFILE}" echo '' case "${AUTO_INSTALL}" in [Yy][Ee][Ss]) echo '' if mm_install "${COMPFILE}"; then echo " *** ${COMPFILE} installed successfully" echo '' # Make the list print one file per line AUTO_INSTALLED_FILES="${AUTO_INSTALLED_FILES} ${DESTDIR}${COMPFILE#.} " else echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand" fi return ;; *) NO_INSTALLED=yes ;; esac fi echo " Use 'd' to delete the temporary ${COMPFILE}" echo " Use 'i' to install the temporary ${COMPFILE}" case "${NO_INSTALLED}" in '') echo " Use 'm' to merge the temporary and installed versions" echo " Use 'v' to view the diff results again" ;; esac echo '' echo " Default is to leave the temporary file to deal with by hand" echo '' echo -n "How should I deal with this? [Leave it for later] " read HANDLE_COMPFILE case "${HANDLE_COMPFILE}" in [dD]) rm "${COMPFILE}" echo '' echo " *** Deleting ${COMPFILE}" ;; [iI]) echo '' if mm_install "${COMPFILE}"; then echo " *** ${COMPFILE} installed successfully" else echo " *** Problem installing ${COMPFILE}, it will remain to merge by hand" fi ;; [mM]) case "${NO_INSTALLED}" in '') # interact with user to merge files merge_loop ;; *) echo '' echo " *** There is no installed version of ${COMPFILE}" echo '' HANDLE_COMPFILE="NOT V" ;; esac # End of "No installed version of file but user selected merge" test ;; [vV]) continue ;; '') echo '' echo " *** ${COMPFILE} will remain for your consideration" ;; *) # invalid choice, show menu again. echo "invalid choice: ${HANDLE_COMPFILE}" echo '' HANDLE_COMPFILE="NOT V" continue ;; esac # End of "How to handle files that are different" done unset NO_INSTALLED echo '' case "${VERBOSE}" in '') ;; *) sleep 3 ;; esac } press_to_continue () { local DISCARD echo -n ' *** Press the [Enter] or [Return] key to continue ' read DISCARD } # Set the default path for the temporary root environment # TEMPROOT='/var/tmp/temproot' # Read /etc/mergemaster.rc first so the one in $HOME can override # if [ -r /etc/mergemaster.rc ]; then . /etc/mergemaster.rc fi # Read .mergemasterrc before command line so CLI can override # if [ -r "$HOME/.mergemasterrc" ]; then . "$HOME/.mergemasterrc" fi for var in "$@" ; do case "$var" in --run-updates*) RUN_UPDATES=`echo ${var#--run-updates=} | tr [:upper:] [:lower:]` ;; *) newopts="$newopts $var" ;; esac done set -- $newopts unset var newopts # Check the command line options # while getopts ":ascrvhipCPm:t:du:w:D:A:FU" COMMAND_LINE_ARGUMENT ; do case "${COMMAND_LINE_ARGUMENT}" in A) ARCHSTRING='TARGET_ARCH='${OPTARG} ;; F) FREEBSD_ID=yes ;; U) AUTO_UPGRADE=yes ;; s) STRICT=yes unset DIFF_OPTIONS ;; c) DIFF_FLAG='-c' ;; r) RERUN=yes ;; v) case "${AUTO_RUN}" in '') VERBOSE=yes ;; esac ;; a) AUTO_RUN=yes unset VERBOSE ;; h) display_usage display_help exit 0 ;; i) AUTO_INSTALL=yes ;; C) COMP_CONFS=yes ;; P) PRESERVE_FILES=yes ;; p) PRE_WORLD=yes unset COMP_CONFS unset AUTO_RUN ;; m) SOURCEDIR=${OPTARG} ;; t) TEMPROOT=${OPTARG} ;; d) TEMPROOT=${TEMPROOT}.`date +%m%d.%H.%M` ;; u) NEW_UMASK=${OPTARG} ;; w) SCREEN_WIDTH=${OPTARG} ;; D) DESTDIR=${OPTARG} ;; *) display_usage exit 1 ;; esac done if [ -n "$AUTO_RUN" ]; then if [ -n "$FREEBSD_ID" -o -n "$AUTO_UPGRADE" -o -n "$AUTO_INSTALL" ]; then echo '' echo "*** You have included the -a option along with one or more options" echo ' that indicate that you wish mergemaster to actually make updates' echo ' (-F, -U, or -i), however these options are not compatible.' echo ' Please read mergemaster(8) for more information.' echo '' exit 1 fi fi # Assign the location of the mtree database # MTREEDB=${MTREEDB:-${DESTDIR}/var/db} MTREEFILE="${MTREEDB}/mergemaster.mtree" # Don't force the user to set this in the mergemaster rc file if [ -n "${PRESERVE_FILES}" -a -z "${PRESERVE_FILES_DIR}" ]; then PRESERVE_FILES_DIR=/var/tmp/mergemaster/preserved-files-`date +%y%m%d-%H%M%S` mkdir -p ${PRESERVE_FILES_DIR} fi # Check for the mtree database in DESTDIR case "${AUTO_UPGRADE}" in '') ;; # If the option is not set no need to run the test or warn the user *) if [ ! -s "${MTREEFILE}" ]; then echo '' echo "*** Unable to find mtree database (${MTREEFILE})." echo " Skipping auto-upgrade on this run." echo " It will be created for the next run when this one is complete." echo '' case "${AUTO_RUN}" in '') press_to_continue ;; esac unset AUTO_UPGRADE fi ;; esac if [ -e "${DESTDIR}/etc/fstab" ]; then if grep -q nodev ${DESTDIR}/etc/fstab; then echo '' echo "*** You have the deprecated 'nodev' option in ${DESTDIR}/etc/fstab." echo " This can prevent the filesystem from being mounted on reboot." echo " Please update your fstab before continuing." echo " See fstab(5) for more information." echo '' exit 1 fi fi echo '' # If the user has a pager defined, make sure we can run it # case "${DONT_CHECK_PAGER}" in '') check_pager () { while ! type "${PAGER%% *}" >/dev/null; do echo " *** Your PAGER environment variable specifies '${PAGER}', but" echo " due to the limited PATH that I use for security reasons," echo " I cannot execute it. So, what would you like to do?" echo '' echo " Use 'e' to exit mergemaster and fix your PAGER variable" echo " Use 'l' to set PAGER to 'less' for this run" echo " Use 'm' to use plain old 'more' as your PAGER for this run" echo '' echo " or you may type an absolute path to PAGER for this run" echo '' - echo " Default is to use plain old 'more' " + echo " Default is to use 'less' " echo '' - echo -n "What should I do? [Use 'more'] " + echo -n "What should I do? [Use 'less'] " read FIXPAGER case "${FIXPAGER}" in [eE]) exit 0 ;; - [lL]) + [lL]|'') PAGER=less ;; - [mM]|'') + [mM]) PAGER=more ;; /*) PAGER="$FIXPAGER" ;; *) echo '' echo "invalid choice: ${FIXPAGER}" esac echo '' done } if [ -n "${PAGER}" ]; then check_pager fi ;; esac # If user has a pager defined, or got assigned one above, use it. -# If not, use more. +# If not, use less. # -PAGER=${PAGER:-more} +PAGER=${PAGER:-less} -if [ -n "${VERBOSE}" -a ! "${PAGER}" = "more" ]; then +if [ -n "${VERBOSE}" -a ! "${PAGER}" = "less" ]; then echo " *** You have ${PAGER} defined as your pager so we will use that" echo '' sleep 3 fi # Assign the diff flag once so we will not have to keep testing it # DIFF_FLAG=${DIFF_FLAG:--u} # Assign the source directory # SOURCEDIR=${SOURCEDIR:-/usr/src} if [ ! -f ${SOURCEDIR}/Makefile.inc1 -a \ -f ${SOURCEDIR}/../Makefile.inc1 ]; then echo " *** The source directory you specified (${SOURCEDIR})" echo " will be reset to ${SOURCEDIR}/.." echo '' sleep 3 SOURCEDIR=${SOURCEDIR}/.. fi SOURCEDIR=$(realpath "$SOURCEDIR") # Setup make to use system files from SOURCEDIR MM_MAKE="make ${ARCHSTRING} -m ${SOURCEDIR}/share/mk -DNO_FILEMON" # Check DESTDIR against the mergemaster mtree database to see what # files the user changed from the reference files. # if [ -n "${AUTO_UPGRADE}" -a -s "${MTREEFILE}" ]; then # Force FreeBSD 9 compatible output when available. if mtree -F freebsd9 -c -p /var/empty/ > /dev/null 2>&1; then MTREE_FLAVOR="-F freebsd9" else MTREE_FLAVOR= fi CHANGED=: for file in `mtree -eqL ${MTREE_FLAVOR} -f ${MTREEFILE} -p ${DESTDIR}/ \ 2>/dev/null | awk '($2 == "changed") {print $1}'`; do if [ -f "${DESTDIR}/$file" ]; then CHANGED="${CHANGED}${DESTDIR}/${file}:" fi done [ "$CHANGED" = ':' ] && unset CHANGED fi # Check the width of the user's terminal # if [ -t 0 ]; then w=`tput columns` case "${w}" in 0|'') ;; # No-op, since the input is not valid *) case "${SCREEN_WIDTH}" in '') SCREEN_WIDTH="${w}" ;; "${w}") ;; # No-op, since they are the same *) echo -n "*** You entered ${SCREEN_WIDTH} as your screen width, but stty " echo "thinks it is ${w}." echo '' echo -n "What would you like to use? [${w}] " read SCREEN_WIDTH case "${SCREEN_WIDTH}" in '') SCREEN_WIDTH="${w}" ;; esac ;; esac esac fi # Define what $Id tag to look for to aid portability. # ID_TAG=FreeBSD delete_temproot () { rm -rf "${TEMPROOT}" 2>/dev/null chflags -R 0 "${TEMPROOT}" 2>/dev/null rm -rf "${TEMPROOT}" || { echo "*** Unable to delete ${TEMPROOT}"; exit 1; } } case "${RERUN}" in '') # Set up the loop to test for the existence of the # temp root directory. # TEST_TEMP_ROOT=yes while [ "${TEST_TEMP_ROOT}" = "yes" ]; do if [ -d "${TEMPROOT}" ]; then echo "*** The directory specified for the temporary root environment," echo " ${TEMPROOT}, exists. This can be a security risk if untrusted" echo " users have access to the system." echo '' case "${AUTO_RUN}" in '') echo " Use 'd' to delete the old ${TEMPROOT} and continue" echo " Use 't' to select a new temporary root directory" echo " Use 'e' to exit mergemaster" echo '' echo " Default is to use ${TEMPROOT} as is" echo '' echo -n "How should I deal with this? [Use the existing ${TEMPROOT}] " read DELORNOT case "${DELORNOT}" in [dD]) echo '' echo " *** Deleting the old ${TEMPROOT}" echo '' delete_temproot unset TEST_TEMP_ROOT ;; [tT]) echo " *** Enter new directory name for temporary root environment" read TEMPROOT ;; [eE]) exit 0 ;; '') echo '' echo " *** Leaving ${TEMPROOT} intact" echo '' unset TEST_TEMP_ROOT ;; *) echo '' echo "invalid choice: ${DELORNOT}" echo '' ;; esac ;; *) # If this is an auto-run, try a hopefully safe alternative then # re-test anyway. TEMPROOT=/var/tmp/temproot.`date +%m%d.%H.%M.%S` ;; esac else unset TEST_TEMP_ROOT fi done echo "*** Creating the temporary root environment in ${TEMPROOT}" if mkdir -p "${TEMPROOT}"; then echo " *** ${TEMPROOT} ready for use" fi if [ ! -d "${TEMPROOT}" ]; then echo '' echo " *** FATAL ERROR: Cannot create ${TEMPROOT}" echo '' exit 1 fi echo " *** Creating and populating directory structure in ${TEMPROOT}" echo '' case "${VERBOSE}" in '') ;; *) press_to_continue ;; esac case "${PRE_WORLD}" in '') { cd ${SOURCEDIR} && case "${DESTDIR}" in '') ;; *) ${MM_MAKE} DESTDIR=${DESTDIR} distrib-dirs >/dev/null ;; esac ${MM_MAKE} DESTDIR=${TEMPROOT} distrib-dirs >/dev/null && ${MM_MAKE} _obj SUBDIR_OVERRIDE=etc >/dev/null && ${MM_MAKE} everything SUBDIR_OVERRIDE=etc >/dev/null && ${MM_MAKE} DESTDIR=${TEMPROOT} distribution >/dev/null;} || { echo ''; echo " *** FATAL ERROR: Cannot 'cd' to ${SOURCEDIR} and install files to"; echo " the temproot environment"; echo ''; exit 1;} ;; *) # Only set up files that are crucial to {build|install}world { mkdir -p ${TEMPROOT}/etc && cp -p ${SOURCEDIR}/etc/master.passwd ${TEMPROOT}/etc && install -p -o root -g wheel -m 0644 ${SOURCEDIR}/etc/group ${TEMPROOT}/etc;} || { echo ''; echo ' *** FATAL ERROR: Cannot copy files to the temproot environment'; echo ''; exit 1;} ;; esac # Doing the inventory and removing files that we don't want to compare only # makes sense if we are not doing a rerun, since we have no way of knowing # what happened to the files during previous incarnations. case "${VERBOSE}" in '') ;; *) echo '' echo ' *** The following files exist only in the installed version of' echo " ${DESTDIR}/etc. In the vast majority of cases these files" echo ' are necessary parts of the system and should not be deleted.' echo ' However because these files are not updated by this process you' echo ' might want to verify their status before rebooting your system.' echo '' press_to_continue diff -qr ${DESTDIR}/etc ${TEMPROOT}/etc | grep "^Only in ${DESTDIR}/etc" | ${PAGER} echo '' press_to_continue ;; esac case "${IGNORE_MOTD}" in '') ;; *) echo '' echo "*** You have the IGNORE_MOTD option set in your mergemaster rc file." echo " This option is deprecated in favor of the IGNORE_FILES option." echo " Please update your rc file accordingly." echo '' exit 1 ;; esac # Avoid comparing the following user specified files for file in ${IGNORE_FILES}; do test -e ${TEMPROOT}/${file} && unlink ${TEMPROOT}/${file} done # We really don't want to have to deal with files like login.conf.db, pwd.db, # or spwd.db. Instead, we want to compare the text versions, and run *_mkdb. # Prompt the user to do so below, as needed. # rm -f ${TEMPROOT}/etc/*.db ${TEMPROOT}/etc/passwd \ ${TEMPROOT}/var/db/services.db # We only need to compare things like freebsd.cf once find ${TEMPROOT}/usr/obj -type f -delete 2>/dev/null # Delete stuff we do not need to keep the mtree database small, # and to make the actual comparison faster. find ${TEMPROOT}/usr -type l -delete 2>/dev/null find ${TEMPROOT} -type f -size 0 -delete 2>/dev/null find -d ${TEMPROOT} -type d -empty -mindepth 1 -delete 2>/dev/null # Build the mtree database in a temporary location. case "${PRE_WORLD}" in '') MTREENEW=`mktemp -t mergemaster.mtree` mtree -nci -p ${TEMPROOT} -k size,md5digest > ${MTREENEW} 2>/dev/null ;; *) # We don't want to mess with the mtree database on a pre-world run or # when re-scanning a previously-built tree. ;; esac ;; # End of the "RERUN" test esac # Get ready to start comparing files # Check umask if not specified on the command line, # and we are not doing an autorun # if [ -z "${NEW_UMASK}" -a -z "${AUTO_RUN}" ]; then USER_UMASK=`umask` case "${USER_UMASK}" in 0022|022) ;; *) echo '' echo " *** Your umask is currently set to ${USER_UMASK}. By default, this script" echo " installs all files with the same user, group and modes that" echo " they are created with by ${SOURCEDIR}/etc/Makefile, compared to" echo " a umask of 022. This umask allows world read permission when" echo " the file's default permissions have it." echo '' echo " No world permissions can sometimes cause problems. A umask of" echo " 022 will restore the default behavior, but is not mandatory." echo " /etc/master.passwd is a special case. Its file permissions" echo " will be 600 (rw-------) if installed." echo '' echo -n "What umask should I use? [${USER_UMASK}] " read NEW_UMASK NEW_UMASK="${NEW_UMASK:-$USER_UMASK}" ;; esac echo '' fi CONFIRMED_UMASK=${NEW_UMASK:-0022} # # Warn users who still have old rc files # for file in atm devfs diskless1 diskless2 network network6 pccard \ serial syscons sysctl alpha amd64 i386 sparc64; do if [ -f "${DESTDIR}/etc/rc.${file}" ]; then OLD_RC_PRESENT=1 break fi done case "${OLD_RC_PRESENT}" in 1) echo '' echo " *** There are elements of the old rc system in ${DESTDIR}/etc/." echo '' echo ' While these scripts will not hurt anything, they are not' echo ' functional on an up to date system, and can be removed.' echo '' case "${AUTO_RUN}" in '') echo -n 'Move these files to /var/tmp/mergemaster/old_rc? [yes] ' read MOVE_OLD_RC case "${MOVE_OLD_RC}" in [nN]*) ;; *) mkdir -p /var/tmp/mergemaster/old_rc for file in atm devfs diskless1 diskless2 network network6 pccard \ serial syscons sysctl alpha amd64 i386 sparc64; do if [ -f "${DESTDIR}/etc/rc.${file}" ]; then mv ${DESTDIR}/etc/rc.${file} /var/tmp/mergemaster/old_rc/ fi done echo ' The files have been moved' press_to_continue ;; esac ;; *) ;; esac esac # Use the umask/mode information to install the files # Create directories as needed # install_error () { echo "*** FATAL ERROR: Unable to install ${1} to ${2}" echo '' exit 1 } do_install_and_rm () { case "${PRESERVE_FILES}" in [Yy][Ee][Ss]) if [ -f "${3}/${2##*/}" ]; then mkdir -p ${PRESERVE_FILES_DIR}/${2%/*} cp ${3}/${2##*/} ${PRESERVE_FILES_DIR}/${2%/*} fi ;; esac if [ ! -d "${3}/${2##*/}" ]; then if install -m ${1} ${2} ${3}; then unlink ${2} else install_error ${2} ${3} fi else install_error ${2} ${3} fi } # 4095 = "obase=10;ibase=8;07777" | bc find_mode () { local OCTAL OCTAL=$(( ~$(echo "obase=10; ibase=8; ${CONFIRMED_UMASK}" | bc) & 4095 & $(echo "obase=10; ibase=8; $(stat -f "%OMp%OLp" ${1})" | bc) )) printf "%04o\n" ${OCTAL} } mm_install () { local INSTALL_DIR INSTALL_DIR=${1#.} INSTALL_DIR=${INSTALL_DIR%/*} case "${INSTALL_DIR}" in '') INSTALL_DIR=/ ;; esac if [ -n "${DESTDIR}${INSTALL_DIR}" -a ! -d "${DESTDIR}${INSTALL_DIR}" ]; then DIR_MODE=`find_mode "${TEMPROOT}/${INSTALL_DIR}"` install -d -o root -g wheel -m "${DIR_MODE}" "${DESTDIR}${INSTALL_DIR}" || install_error $1 ${DESTDIR}${INSTALL_DIR} fi FILE_MODE=`find_mode "${1}"` if [ ! -x "${1}" ]; then case "${1#.}" in /etc/mail/aliases) NEED_NEWALIASES=yes ;; /etc/login.conf) NEED_CAP_MKDB=yes ;; /etc/services) NEED_SERVICES_MKDB=yes ;; /etc/master.passwd) do_install_and_rm 600 "${1}" "${DESTDIR}${INSTALL_DIR}" NEED_PWD_MKDB=yes DONT_INSTALL=yes ;; /.cshrc | /.profile) local st_nlink # install will unlink the file before it installs the new one, # so we have to restore/create the link afterwards. # st_nlink=0 # In case the file does not yet exist eval $(stat -s ${DESTDIR}${COMPFILE#.} 2>/dev/null) do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}" if [ -n "${AUTO_INSTALL}" -a $st_nlink -gt 1 ]; then HANDLE_LINK=l else case "${LINK_EXPLAINED}" in '') echo " *** Historically BSD derived systems have had a" echo " hard link from /.cshrc and /.profile to" echo " their namesakes in /root. Please indicate" echo " your preference below for bringing your" echo " installed files up to date." echo '' LINK_EXPLAINED=yes ;; esac echo " Use 'd' to delete the temporary ${COMPFILE}" echo " Use 'l' to delete the existing ${DESTDIR}/root/${COMPFILE##*/} and create the link" echo '' echo " Default is to leave the temporary file to deal with by hand" echo '' echo -n " How should I handle ${COMPFILE}? [Leave it to install later] " read HANDLE_LINK fi case "${HANDLE_LINK}" in [dD]*) rm "${COMPFILE}" echo '' echo " *** Deleting ${COMPFILE}" ;; [lL]*) echo '' unlink ${DESTDIR}/root/${COMPFILE##*/} if ln ${DESTDIR}${COMPFILE#.} ${DESTDIR}/root/${COMPFILE##*/}; then echo " *** Link from ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/} installed successfully" else echo " *** Error linking ${DESTDIR}${COMPFILE#.} to ${DESTDIR}/root/${COMPFILE##*/}" echo " *** ${COMPFILE} will remain for your consideration" fi ;; *) echo " *** ${COMPFILE} will remain for your consideration" ;; esac return ;; esac case "${DONT_INSTALL}" in '') do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}" ;; *) unset DONT_INSTALL ;; esac else # File matched -x do_install_and_rm "${FILE_MODE}" "${1}" "${DESTDIR}${INSTALL_DIR}" fi return $? } if [ ! -d "${TEMPROOT}" ]; then echo "*** FATAL ERROR: The temproot directory (${TEMPROOT})" echo ' has disappeared!' echo '' exit 1 fi echo '' echo "*** Beginning comparison" echo '' # Pre-world does not populate /etc/rc.d. # It is very possible that a previous run would have deleted files in # ${TEMPROOT}/etc/rc.d, thus creating a lot of false positives. if [ -z "${PRE_WORLD}" -a -z "${RERUN}" ]; then echo " *** Checking ${DESTDIR}/etc/rc.d for stale files" echo '' cd "${DESTDIR}/etc/rc.d" && for file in *; do if [ ! -e "${TEMPROOT}/etc/rc.d/${file}" ]; then STALE_RC_FILES="${STALE_RC_FILES} ${file}" fi done case "${STALE_RC_FILES}" in ''|' *') echo ' *** No stale files found' ;; *) echo " *** The following files exist in ${DESTDIR}/etc/rc.d but not in" echo " ${TEMPROOT}/etc/rc.d/:" echo '' echo "${STALE_RC_FILES}" echo '' echo ' The presence of stale files in this directory can cause the' echo ' dreaded unpredictable results, and therefore it is highly' echo ' recommended that you delete them.' case "${AUTO_RUN}" in '') echo '' echo -n ' *** Delete them now? [n] ' read DELETE_STALE_RC_FILES case "${DELETE_STALE_RC_FILES}" in [yY]) echo ' *** Deleting ... ' rm ${STALE_RC_FILES} echo ' done.' ;; *) echo ' *** Files will not be deleted' ;; esac sleep 2 ;; *) if [ -n "${DELETE_STALE_RC_FILES}" ]; then echo ' *** Deleting ... ' rm ${STALE_RC_FILES} echo ' done.' fi esac ;; esac echo '' fi cd "${TEMPROOT}" if [ -r "${MM_PRE_COMPARE_SCRIPT}" ]; then . "${MM_PRE_COMPARE_SCRIPT}" fi # Things that were files/directories/links in one version can sometimes # change to something else in a newer version. So we need to explicitly # test for this, and warn the user if what we find does not match. # for COMPFILE in `find . | sort` ; do if [ -e "${DESTDIR}${COMPFILE#.}" ]; then INSTALLED_TYPE=`stat -f '%HT' ${DESTDIR}${COMPFILE#.}` else continue fi TEMPROOT_TYPE=`stat -f '%HT' $COMPFILE` if [ ! "$TEMPROOT_TYPE" = "$INSTALLED_TYPE" ]; then [ "$COMPFILE" = '.' ] && continue TEMPROOT_TYPE=`echo $TEMPROOT_TYPE | tr [:upper:] [:lower:]` INSTALLED_TYPE=`echo $INSTALLED_TYPE | tr [:upper:] [:lower:]` echo "*** The installed file ${DESTDIR}${COMPFILE#.} has the type \"$INSTALLED_TYPE\"" echo " but the new version has the type \"$TEMPROOT_TYPE\"" echo '' echo " How would you like to handle this?" echo '' echo " Use 'r' to remove ${DESTDIR}${COMPFILE#.}" case "$TEMPROOT_TYPE" in 'symbolic link') TARGET=`readlink $COMPFILE` echo " and create a link to $TARGET in its place" ;; *) echo " You will be able to install it as a \"$TEMPROOT_TYPE\"" ;; esac echo '' echo " Use 'i' to ignore this" echo '' echo -n " How to proceed? [i] " read ANSWER case "$ANSWER" in [rR]) case "${PRESERVE_FILES}" in [Yy][Ee][Ss]) mv ${DESTDIR}${COMPFILE#.} ${PRESERVE_FILES_DIR}/ || exit 1 ;; *) rm -rf ${DESTDIR}${COMPFILE#.} ;; esac case "$TEMPROOT_TYPE" in 'symbolic link') ln -sf $TARGET ${DESTDIR}${COMPFILE#.} ;; esac ;; *) echo '' echo "*** See the man page about adding ${COMPFILE#.} to the list of IGNORE_FILES" press_to_continue ;; esac echo '' fi done for COMPFILE in `find . -type f | sort`; do # First, check to see if the file exists in DESTDIR. If not, the # diff_loop function knows how to handle it. # if [ ! -e "${DESTDIR}${COMPFILE#.}" ]; then case "${AUTO_RUN}" in '') diff_loop ;; *) case "${AUTO_INSTALL}" in '') # If this is an auto run, make it official echo " *** ${COMPFILE} will remain for your consideration" ;; *) diff_loop ;; esac ;; esac # Auto run test continue fi case "${STRICT}" in '' | [Nn][Oo]) # Compare $Id's first so if the file hasn't been modified # local changes will be ignored. # If the files have the same $Id, delete the one in temproot so the # user will have less to wade through if files are left to merge by hand. # ID1=`grep "[$]${ID_TAG}:" ${DESTDIR}${COMPFILE#.} 2>/dev/null` ID2=`grep "[$]${ID_TAG}:" ${COMPFILE} 2>/dev/null` || ID2=none case "${ID2}" in "${ID1}") echo " *** Temp ${COMPFILE} and installed have the same Id, deleting" rm "${COMPFILE}" ;; esac ;; esac # If the file is still here either because the $Ids are different, the # file doesn't have an $Id, or we're using STRICT mode; look at the diff. # if [ -f "${COMPFILE}" ]; then # Do an absolute diff first to see if the files are actually different. # If they're not different, delete the one in temproot. # if diff -q ${DIFF_OPTIONS} "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > \ /dev/null 2>&1; then echo " *** Temp ${COMPFILE} and installed are the same, deleting" rm "${COMPFILE}" else # Ok, the files are different, so show the user where they differ. # Use user's choice of diff methods; and user's pager if they have one. - # Use more if not. + # Use less if not. # Use unified diffs by default. Context diffs give me a headache. :) # # If the user chose the -F option, test for that before proceeding # if [ -n "$FREEBSD_ID" ]; then if diff -q -I'[$]FreeBSD.*[$]' "${DESTDIR}${COMPFILE#.}" "${COMPFILE}" > \ /dev/null 2>&1; then if mm_install "${COMPFILE}"; then echo "*** Updated revision control Id for ${DESTDIR}${COMPFILE#.}" else echo "*** Problem installing ${COMPFILE}, it will remain to merge by hand later" fi continue fi fi case "${AUTO_RUN}" in '') # prompt user to install/delete/merge changes diff_loop ;; *) # If this is an auto run, make it official echo " *** ${COMPFILE} will remain for your consideration" ;; esac # Auto run test fi # Yes, the files are different fi # Yes, the file still remains to be checked done # This is for the for way up there at the beginning of the comparison echo '' echo "*** Comparison complete" if [ -s "${MTREENEW}" ]; then echo "*** Saving mtree database for future upgrades" test -e "${MTREEFILE}" && unlink ${MTREEFILE} mv ${MTREENEW} ${MTREEFILE} fi echo '' TEST_FOR_FILES=`find ${TEMPROOT} -type f -size +0 2>/dev/null` if [ -n "${TEST_FOR_FILES}" ]; then echo "*** Files that remain for you to merge by hand:" find "${TEMPROOT}" -type f -size +0 | sort echo '' case "${AUTO_RUN}" in '') echo -n "Do you wish to delete what is left of ${TEMPROOT}? [no] " read DEL_TEMPROOT case "${DEL_TEMPROOT}" in [yY]*) delete_temproot ;; *) echo " *** ${TEMPROOT} will remain" ;; esac ;; *) ;; esac else echo "*** ${TEMPROOT} is empty, deleting" delete_temproot fi case "${AUTO_INSTALLED_FILES}" in '') ;; *) case "${AUTO_RUN}" in '') ( echo '' echo '*** You chose the automatic install option for files that did not' echo ' exist on your system. The following were installed for you:' echo "${AUTO_INSTALLED_FILES}" ) | ${PAGER} ;; *) echo '' echo '*** You chose the automatic install option for files that did not' echo ' exist on your system. The following were installed for you:' echo "${AUTO_INSTALLED_FILES}" ;; esac ;; esac case "${AUTO_UPGRADED_FILES}" in '') ;; *) case "${AUTO_RUN}" in '') ( echo '' echo '*** You chose the automatic upgrade option for files that you did' echo ' not alter on your system. The following were upgraded for you:' echo "${AUTO_UPGRADED_FILES}" ) | ${PAGER} ;; *) echo '' echo '*** You chose the automatic upgrade option for files that you did' echo ' not alter on your system. The following were upgraded for you:' echo "${AUTO_UPGRADED_FILES}" ;; esac ;; esac run_it_now () { [ -n "$AUTO_RUN" ] && return local answer echo '' while : ; do if [ "$RUN_UPDATES" = always ]; then answer=y elif [ "$RUN_UPDATES" = never ]; then answer=n else echo -n ' Would you like to run it now? y or n [n] ' read answer fi case "$answer" in y) echo " Running ${1}" echo '' eval "${1}" return ;; ''|n) if [ ! "$RUN_UPDATES" = never ]; then echo '' echo " *** Cancelled" echo '' fi echo " Make sure to run ${1} yourself" return ;; *) echo '' echo " *** Sorry, I do not understand your answer (${answer})" echo '' esac done } case "${NEED_NEWALIASES}" in '') ;; *) echo '' if [ -n "${DESTDIR}" ]; then echo "*** You installed a new aliases file into ${DESTDIR}/etc/mail, but" echo " the newaliases command is limited to the directories configured" echo " in sendmail.cf. Make sure to create your aliases database by" echo " hand when your sendmail configuration is done." else echo "*** You installed a new aliases file, so make sure that you run" echo " '/usr/bin/newaliases' to rebuild your aliases database" run_it_now '/usr/bin/newaliases' fi ;; esac case "${NEED_CAP_MKDB}" in '') ;; *) echo '' echo "*** You installed a login.conf file, so make sure that you run" echo " '/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf'" echo " to rebuild your login.conf database" run_it_now "/usr/bin/cap_mkdb ${DESTDIR}/etc/login.conf" ;; esac case "${NEED_SERVICES_MKDB}" in '') ;; *) echo '' echo "*** You installed a services file, so make sure that you run" echo " '/usr/sbin/services_mkdb -q -o ${DESTDIR}/var/db/services.db ${DESTDIR}/etc/services'" echo " to rebuild your services database" run_it_now "/usr/sbin/services_mkdb -q -o ${DESTDIR}/var/db/services.db ${DESTDIR}/etc/services" ;; esac case "${NEED_PWD_MKDB}" in '') ;; *) echo '' echo "*** You installed a new master.passwd file, so make sure that you run" if [ -n "${DESTDIR}" ]; then echo " '/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd'" echo " to rebuild your password files" run_it_now "/usr/sbin/pwd_mkdb -d ${DESTDIR}/etc -p ${DESTDIR}/etc/master.passwd" else echo " '/usr/sbin/pwd_mkdb -p /etc/master.passwd'" echo " to rebuild your password files" run_it_now '/usr/sbin/pwd_mkdb -p /etc/master.passwd' fi ;; esac if [ -e "${DESTDIR}/etc/localtime" -a ! -L "${DESTDIR}/etc/localtime" -a -z "${PRE_WORLD}" ]; then # Ignore if TZ == UTC echo '' [ -n "${DESTDIR}" ] && tzs_args="-C ${DESTDIR}" if [ -f "${DESTDIR}/var/db/zoneinfo" ]; then echo "*** Reinstalling `cat ${DESTDIR}/var/db/zoneinfo` as ${DESTDIR}/etc/localtime" tzsetup $tzs_args -r else echo "*** There is no ${DESTDIR}/var/db/zoneinfo file to update ${DESTDIR}/etc/localtime." echo ' You should run tzsetup' run_it_now "tzsetup $tzs_args" fi fi echo '' if [ -r "${MM_EXIT_SCRIPT}" ]; then . "${MM_EXIT_SCRIPT}" fi case "${COMP_CONFS}" in '') ;; *) . ${DESTDIR}/etc/defaults/rc.conf (echo '' echo "*** Comparing conf files: ${rc_conf_files}" for CONF_FILE in ${rc_conf_files}; do if [ -r "${DESTDIR}${CONF_FILE}" ]; then echo '' echo "*** From ${DESTDIR}${CONF_FILE}" echo "*** From ${DESTDIR}/etc/defaults/rc.conf" for RC_CONF_VAR in `grep -i ^[a-z] ${DESTDIR}${CONF_FILE} | cut -d '=' -f 1`; do echo '' grep -w ^${RC_CONF_VAR} ${DESTDIR}${CONF_FILE} grep -w ^${RC_CONF_VAR} ${DESTDIR}/etc/defaults/rc.conf || echo ' * No default variable with this name' done fi done) | ${PAGER} echo '' ;; esac if [ -n "${PRESERVE_FILES}" ]; then find -d $PRESERVE_FILES_DIR -type d -empty -delete 2>/dev/null rmdir $PRESERVE_FILES_DIR 2>/dev/null fi exit 0 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Copyright (c) 1998-2012 Douglas Barton # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must 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.